演習: ArrayList
各問題のコードは、Main クラスの main メソッドの中に書く前提です。ArrayList を使うには import java.util.ArrayList; が必要です。
ArrayList は 動的サイズの配列 のような型で、配列と違って要素数が後から自由に変えられます。基本的な使い方:
import java.util.ArrayList;
public class Main { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(10); list.add(20); System.out.println(list.size()); // 2 System.out.println(list.get(0)); // 10 }}ArrayList<型> の 型 は 参照型 である必要があり、プリミティブ型(int、double など)はそのままでは使えません。代わりに Integer や Double などの ラッパークラス を使います。Java が自動で変換するので、list.add(10) のように int のリテラルをそのまま渡すこともできます。
7-A. ArrayList の作成と表示
Section titled “7-A. ArrayList の作成と表示”整数を要素に持つ ArrayList<Integer> を作り、10, 20, 30, 40, 50 の5つの要素を追加してください。最後に、要素数: に続けて要素数を、次の行に全要素を出力します。
出力例:
要素数: 5[10, 20, 30, 40, 50]ヒント
ArrayList<Integer> のインスタンス化:
ArrayList<Integer> list = new ArrayList<>();右辺の <> は ダイヤモンド演算子 と呼ばれ、左辺の型から型推論されます。
要素の追加には add(値) メソッドを使います。要素数は size()、全要素は System.out.println(list) で自動的に [10, 20, 30, ...] の形式で表示されます。
7-B. 要素の追加と取得(add, get, size)
Section titled “7-B. 要素の追加と取得(add, get, size)”ArrayList<String> を作り、果物の名前を3つ追加します("apple"、"banana"、"cherry")。その後、インデックス指定で各要素を取り出して、インデックス: 要素 の形式で1行ずつ出力してください。
出力例:
0: apple1: banana2: cherryヒント
要素の追加: list.add(値)(末尾に追加)。
インデックス指定の取得: list.get(インデックス)。
for ループで i を 0 から list.size() - 1 まで進め、各位置の要素を取り出します。
7-C. 要素の削除と更新(remove, set)
Section titled “7-C. 要素の削除と更新(remove, set)”ArrayList<String> に "apple"、"banana"、"cherry"、"date" を追加した状態から、次の操作を順に行い、各操作後の ArrayList の内容を出力してください。
- インデックス
1の要素を削除する - 末尾に
"elderberry"を追加する - インデックス
0の要素を"avocado"に変更する
出力例:
初期状態: [apple, banana, cherry, date]1の削除後: [apple, cherry, date]追加後: [apple, cherry, date, elderberry]更新後: [avocado, cherry, date, elderberry]ヒント
- 削除:
list.remove(インデックス)でその位置の要素を削除(後続の要素が前にずれる) - 追加:
list.add(値)で末尾に追加 - 更新:
list.set(インデックス, 新しい値)でその位置の要素を置き換え
7-D. 拡張 for で走査
Section titled “7-D. 拡張 for で走査”ArrayList<Integer> に 3, 1, 4, 1, 5, 9, 2, 6 を追加し、拡張 for 文で全要素を半角スペース区切りで1行に出力してください。
出力例:
3 1 4 1 5 9 2 6ヒント
拡張 for 文は ArrayList にも使えます。要素の型は Integer(または int でも可)として受け取ります。int で受け取ると、Integer から自動で変換されます。
要素間の区切りには半角スペースを手動で挿入する必要があります(5-A. 配列の宣言と表示と同じ)。
7-E. 合計と平均
Section titled “7-E. 合計と平均”ArrayList<Integer> を受け取り、合計と平均を出力してください。平均は小数で表示します。
ArrayList<Integer> scores = new ArrayList<>();scores.add(72);scores.add(85);scores.add(64);scores.add(90);scores.add(78);出力例:
合計: 389平均: 77.8ヒント
for または拡張 for で ArrayList を走査し、合計を計算します。平均は (double) 合計 / list.size() でキャストが必要です(整数除算を避けるため)。
7-F. 最大値の探索
Section titled “7-F. 最大値の探索”ArrayList<Integer> の最大値を出力してください。
ArrayList<Integer> numbers = new ArrayList<>();numbers.add(15);numbers.add(22);numbers.add(18);numbers.add(30);numbers.add(25);numbers.add(17);numbers.add(28);出力例:
最大値: 30ヒント
list.get(0) を仮の最大値とし、インデックス 1 以降と順に比較していきます(5-C. 最大値と同じ考え方を ArrayList で行います)。
7-G. 特定値の検索(contains, indexOf)
Section titled “7-G. 特定値の検索(contains, indexOf)”ArrayList<String> に対して、指定した値が含まれているかどうかと、含まれている場合は最初のインデックスを出力してください。
ArrayList<String> fruits = new ArrayList<>();fruits.add("apple");fruits.add("banana");fruits.add("cherry");fruits.add("banana");fruits.add("date");
String target1 = "banana";String target2 = "grape";出力例:
banana: あり (最初の位置: 1)grape: なしヒント
list.contains(値): その値が含まれていればtrue、なければfalseを返すlist.indexOf(値): 最初に現れる位置のインデックスを返す。見つからなければ-1
contains の結果で if 分岐し、見つかった場合に indexOf で位置を取得します。indexOf だけ使って、-1 かどうかで判定する書き方もできます。
7-H. 2つの ArrayList の連結
Section titled “7-H. 2つの ArrayList の連結”2つの ArrayList<Integer> を、list1 の後ろに list2 をつなげる形で連結させ、結果を出力してください。元の list1 を直接書き換えます。
ArrayList<Integer> list1 = new ArrayList<>();list1.add(1);list1.add(2);list1.add(3);
ArrayList<Integer> list2 = new ArrayList<>();list2.add(10);list2.add(20);list2.add(30);出力例:
連結後: [1, 2, 3, 10, 20, 30]ヒント
addAll メソッドを使うと、別の ArrayList の全要素を一度に追加できます:
list1.addAll(list2);または、拡張 for で list2 を走査して、1要素ずつ list1.add(要素) で追加する手動方式でも同じ結果になります。
7-I. 重複の削除
Section titled “7-I. 重複の削除”ArrayList<Integer> から重複する要素を削除し、各値が最初に登場した順序を保ったまま、結果を出力してください。
ArrayList<Integer> numbers = new ArrayList<>();int[] data = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9};for (int n : data) numbers.add(n);出力例:
[3, 1, 4, 5, 9, 2, 6]ヒント
新しい ArrayList<Integer> を1つ用意し、元の ArrayList を走査します。各要素について、新しい方にまだ含まれていなければ追加します。contains メソッドで判定できます。
最後に、元の ArrayList を新しい方で置き換える(または新しい方を結果として使う)。
7-J. Fisher-Yates シャッフル(ArrayList 版)
Section titled “7-J. Fisher-Yates シャッフル(ArrayList 版)”ArrayList<Integer> を Fisher-Yates アルゴリズムでシャッフルし、結果を出力してください。元の ArrayList を直接書き換えます。アルゴリズムは 5-L. Fisher-Yates シャッフルと同じです。
ArrayList<Integer> numbers = new ArrayList<>();for (int i = 1; i <= 10; i++) numbers.add(i);実行ごとに結果が変わります。出力例の1つ:
[3, 7, 1, 9, 4, 10, 2, 8, 5, 6]ヒント
アルゴリズム自体は 5-L. Fisher-Yates シャッフルと同じですが、ArrayList では要素の交換に get / set を使います:
int tmp = list.get(i);list.set(i, list.get(j));list.set(j, tmp);ランダムなインデックス j(0 ≤ j ≤ i)の生成は (int)(Math.random() * (i + 1)) です。
7-K. スタック実装(push / pop / peek)
Section titled “7-K. スタック実装(push / pop / peek)”ArrayList<Integer> を使って、スタック(後入れ先出し、LIFO)の操作を実装してください。次の3つのメソッドを static で定義します:
push(list, value): 末尾に要素を追加(void)pop(list): 末尾の要素を取り出して返す(int、空ならエラー)peek(list): 末尾の要素を見るだけ(取り出さない、int)
main で以下の操作を順に行い、結果を確認します:
ArrayList<Integer> stack = new ArrayList<>();push(stack, 10);push(stack, 20);push(stack, 30);System.out.println("スタック: " + stack);System.out.println("peek: " + peek(stack));System.out.println("pop: " + pop(stack));System.out.println("pop: " + pop(stack));System.out.println("スタック: " + stack);出力例:
スタック: [10, 20, 30]peek: 30pop: 30pop: 20スタック: [10]ヒント
スタックの「末尾」を list.size() - 1 のインデックスとして扱います:
push:list.add(value)で末尾に追加pop:list.remove(list.size() - 1)で末尾を取り出して返すpeek:list.get(list.size() - 1)で末尾を参照(削除しない)
pop / peek で空のスタックに対する操作が呼ばれた場合のエラー処理(例外を投げる、あるいは特殊な値を返す)も考えられますが、呼び出し側が空でないことを保証する前提で構いません。