【JAVA】レッスン4-04:TreeMapを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:TreeMap

この記事の練習問題で使用する知識:
基礎構文、制御構造、メソッド(レッスン1~3)ArrayListHashSetTreeSet、HashMap、TreeMap

<<前の問題 問題集Top 次の問題>>

JAVAの文法「TreeMap」とは

ここではTreeMapの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。




Javaでプログラミングを始めたばかりの方にとって、データ構造を正しく理解することは非常に重要です。

その中でもJavaのコレクションフレームワークに含まれる「TreeMap」は、データを効率的に格納し、検索するために使える便利なクラスです。

本記事ではTreeMapの基本的な使い方を説明し、後半ではよく比較されるHashMapとの違いについても詳しく解説します。

TreeMapとは?

TreeMapはJavaのjava.utilパッケージに含まれるクラスで、キーと値のペア(key-value pair)を保持するマップの一種です。

TreeMapの特徴はキーが自動的にソートされることです。これは内部で赤黒木(Red-Black Tree)というバランスの取れた二分探索木を使っているためです。

そのためTreeMapを使用すると要素を挿入した順番ではなく、キーの自然順序(またはComparatorを使ったカスタム順序)に基づいてソートされます。

TreeMapの基本的な使い方

それでは基本的なTreeMapの使い方を見てみましょう。

import java.util.TreeMap; // TreeMapを使用するためのインポート文

public class TreeMapExample {
    public static void main(String[] args) {
        //Int型のキーとString型の値をもつtreeMapというTreeMapを作成
        TreeMap<Integer, String> treeMap = new TreeMap<>();

        // putメソッドを使って要素を追加
        treeMap.put(3, "三");
        treeMap.put(1, "一");
        treeMap.put(2, "二");

        // 要素の表示
        System.out.println("TreeMapの内容: " + treeMap);

        // getメソッドを使って特定のキーの値を取得
        System.out.println("キー1の値: " + treeMap.get(1));

        // ソートされたキーの一覧を取得
        System.out.println("ソートされたキー: " + treeMap.keySet());
    }
}

このコードを実行すると以下のような結果が得られます:

TreeMapの内容: {1=一, 2=二, 3=三}
キー1の値: 一
ソートされたキー: [1, 2, 3]

TreeMapではキーが自動的にソートされているため、put()メソッドで値を挿入した順番とは異なり、キーが昇順で並び替えられています。

TreeMapの主なメソッド

TreeMapは以下のような便利なメソッドを提供しています。

  • put(K key, V value): キーと値のペアをマップに挿入します。
  • get(Object key): 指定したキーに対応する値を返します。
  • remove(Object key): 指定したキーに対応するエントリを削除します。
  • firstKey(): 最小のキーを返します。
  • lastKey(): 最大のキーを返します。
  • size(): TreeMapに含まれるエントリの数を返します。

TreeMapとHashMapの違い

TreeMapとよく比較されるのがHashMapです。どちらもキーと値のペアを保持するマップですが、それぞれ特徴が異なります。

ここでは両者の違いを簡単にまとめます。

特徴 TreeMap HashMap
ソート順 キーが自然順序またはComparatorでソートされる 挿入順序は保証されない
内部構造 赤黒木を使用 ハッシュテーブルを使用
パフォーマンス データの挿入・削除にO(log n)の時間がかかる O(1)に近い時間で操作が可能
nullの扱い nullキーは許可されない nullキーとnull値の両方が許可される
主な用途 データをソートされた状態で保持したいとき 高速なデータ挿入と取得が必要なとき

TreeMapとHashMapのどちらを使うべきか?

  • データを順序通りに保持したい場合:キーのソートが必要な場面、例えば数値やアルファベット順で要素を処理したいときには、TreeMapが適しています。
  • 高速なデータ操作が必要な場合:順序を気にせず、挿入や検索をできるだけ早く行いたいときは、HashMapを使用する方が効果的です。

例えばアルファベット順にユーザーの名前を管理したい場合はTreeMapを使うと便利ですが、単純にユーザーIDと名前を対応させたいだけなら、HashMapの方が効率的でしょう。

JAVA練習問題4-4:HashMapとTreeMapの違いを理解しよう

あなたは学校の教師で、生徒のテストの点数を管理するプログラムを作成したいと考えています。

生徒の名前とその点数を入力し、それを使って以下の機能を実現するプログラムを作成してください。

この問題の要件

以下の要件を満たすプログラムを作成してください。

  • Scannerクラスを使ってユーザーから生徒の名前と点数を3人分入力すること。
  • HashMapを使用して、入力された生徒の名前と点数を格納すること。
  • HashMapの内容を入力順に表示すること。
  • HashMapの内容をTreeMapにコピーし、名前のアルファベット順に並び替えて表示すること。
  • HashMapの内容を表示するメソッドprintHashMapを作成すること。
  • TreeMapの内容を表示するメソッドprintTreeMapを作成すること。

ただし、以下のような実行結果となること。

----- ↓出力される結果の例↓ -----

生徒の名前を入力してください: 田中
田中の点数を入力してください: 85
生徒の名前を入力してください: 鈴木
鈴木の点数を入力してください: 92
生徒の名前を入力してください: 佐藤
佐藤の点数を入力してください: 78
HashMapを使って入力順に記載:
田中の点数は85点です。
鈴木の点数は92点です。
佐藤の点数は78点です。
TreeMapを使って名前のアルファベット順に記載:
佐藤の点数は78点です。
鈴木の点数は92点です。
田中の点数は85点です。

----- ↑出力される結果の例↑ -----

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:HashMapクラスをインポート
2:Scannerクラスをインポート
3:TreeMapクラスをインポート
4:MapExampleクラスの定義
  □ mainメソッドの定義
  □ □ Scannerオブジェクトscannerの初期化
  □ □ HashMapオブジェクトstudentHashMapの初期化
  □ □ forループを3回繰り返すように設定
  □ □ □ 「生徒の名前を入力してください: 」と出力
  □ □ □ ユーザーの入力を文字列として読み取り、変数nameに代入
  □ □ □ 「[name]の点数を入力してください: 」と出力
  □ □ □ ユーザーの入力を整数として読み取り、変数scoreに代入
  □ □ □ 改行を消費するためにscanner.nextLine()を呼び出し
  □ □ □ studentHashMapにnameとscoreを格納
  □ □ TreeMapオブジェクトstudentTreeMapをstudentHashMapから初期化
  □ □ 「HashMapを使って入力順に記載:」と出力
  □ □ printHashMapメソッドを呼び出し、studentHashMapを渡す
  □ □ 「TreeMapを使って名前のアルファベット順に記載:」と出力
  □ □ printTreeMapメソッドを呼び出し、studentTreeMapを渡す
  □ printHashMapメソッドの定義
  □ □ forループでHashMapのkeySetを走査
  □ □ □ nameに対して対応するscoreを取得し、「[name]の点数は[score]点です。」と出力
  □ printTreeMapメソッドの定義
  □ □ forループでTreeMapのkeySetを走査
  □ □ □ nameに対して対応するscoreを取得し、「[name]の点数は[score]点です。」と出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

import java.util.HashMap;
import java.util.Scanner;
import java.util.TreeMap;

public class MapExample {

    // メインメソッド
    public static void main(String[] args) {
        // スキャナを作成してユーザー入力を受け取る
        Scanner scanner = new Scanner(System.in);

        /*【穴埋め問題1】
        ここで生徒の名前と点数を格納するためのHashMapを作成してください。
        */

        // 3人の生徒の情報を入力してもらう
        for (int i = 0; i < 3; i++) {
            System.out.print("生徒の名前を入力してください: ");
            String name = scanner.nextLine();
            System.out.print(name + "の点数を入力してください: ");
            int score = scanner.nextInt();
            scanner.nextLine(); // 改行を消費する

            /*【穴埋め問題2】
            ここでHashMapにnameとscoreを格納してください。
            */
        }

        /*【穴埋め問題3】
        ここで生徒の名前と点数を格納するTreeMapを作成し、先ほどのHashMapを引数にして初期化してください。
        */

        // HashMapの内容を表示
        System.out.println("HashMapを使って入力順に記載:");

        /*【穴埋め問題4】
        ここでprintHashMapメソッドを呼び出し、studentHashMapを引数として渡してください。
        */

        // TreeMapの内容を表示
        System.out.println("TreeMapを使って名前のアルファベット順に記載:");

        /*【穴埋め問題5】
        ここでprintTreeMapメソッドを呼び出し、studentTreeMapを引数として渡してください。
        */
    }

    // HashMapの内容を表示するメソッド
    public static void printHashMap(HashMap<String, Integer> map) {
        // HashMapから名前と点数を一つずつ取り出して表示
        for (String name : map.keySet()) {
            Integer score = map.get(name);
            System.out.println(name + "の点数は" + score + "点です。");
        }
    }

    // TreeMapの内容を表示するメソッド
    public static void printTreeMap(TreeMap<String, Integer> map) {
        // TreeMapから名前と点数を一つずつ取り出して表示
        for (String name : map.keySet()) {
            Integer score = map.get(name);
            System.out.println(name + "の点数は" + score + "点です。");
        }
    }
}

この問題の穴埋めコードは以上です。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

解答例

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

********************

import java.util.HashMap;
import java.util.Scanner;
import java.util.TreeMap;

public class MapExample {

    // メインメソッド
    public static void main(String[] args) {
        // スキャナを作成してユーザー入力を受け取る
        Scanner scanner = new Scanner(System.in);

        // 生徒の名前と点数を格納するHashMapを作成
        HashMap<String, Integer> studentHashMap = new HashMap<>();

        // 3人の生徒の情報を入力してもらう
        for (int i = 0; i < 3; i++) {
            System.out.print("生徒の名前を入力してください: ");
            String name = scanner.nextLine();
            System.out.print(name + "の点数を入力してください: ");
            int score = scanner.nextInt();
            scanner.nextLine(); // 改行を消費する
            studentHashMap.put(name, score);
        }

        // 生徒の名前と点数を格納するTreeMapを作成
        TreeMap<String, Integer> studentTreeMap = new TreeMap<>(studentHashMap);

        // HashMapの内容を表示
        System.out.println("HashMapを使って入力順に記載:");
        printHashMap(studentHashMap);

        // TreeMapの内容を表示
        System.out.println("TreeMapを使って名前のアルファベット順に記載:");
        printTreeMap(studentTreeMap);
    }

    // HashMapの内容を表示するメソッド
    public static void printHashMap(HashMap<String, Integer> map) {
        // HashMapから名前と点数を一つずつ取り出して表示
        for (String name : map.keySet()) {
            Integer score = map.get(name);
            System.out.println(name + "の点数は" + score + "点です。");
        }
    }

    // TreeMapの内容を表示するメソッド
    public static void printTreeMap(TreeMap<String, Integer> map) {
        // TreeMapから名前と点数を一つずつ取り出して表示
        for (String name : map.keySet()) {
            Integer score = map.get(name);
            System.out.println(name + "の点数は" + score + "点です。");
        }
    }
}

********************

コードの解説

このコードはHashMapTreeMapという2つの異なるマップ構造を使って、生徒の名前と点数を保存し、入力順とアルファベット順にそれぞれ表示するプログラムです。

次のステップで詳細に説明していきます。

スキャナの作成

Scanner scanner = new Scanner(System.in);

この行ではScannerオブジェクトを作成して、ユーザーからの入力を受け取る準備をします。

Scannerはキーボード入力を簡単に処理できる便利なクラスです。

HashMapの作成

HashMap<String, Integer> studentHashMap = new HashMap<>();

HashMapはキーと値をペアで保存するデータ構造です。

この場合キーとして生徒の名前(String型)、値として点数(Integer型)を保存します。

HashMapは順序が保証されていない点が特徴です。

ユーザーから3人の生徒情報を入力

for (int i = 0; i < 3; i++) {
    System.out.print("生徒の名前を入力してください: ");
    String name = scanner.nextLine();
    System.out.print(name + "の点数を入力してください: ");
    int score = scanner.nextInt();
    scanner.nextLine(); // 改行を消費する
    studentHashMap.put(name, score);
}

ここではforループを使って、ユーザーに3人の生徒の名前と点数を入力してもらいます。

そしてそれらのデータをHashMapに格納します。

TreeMapの作成

TreeMapHashMapと同様にキーと値をペアで保存しますが、大きな違いはキーが自然順序(この場合はアルファベット順)に自動的にソートされる点です。

ここではHashMapのデータを元にTreeMapを作成して、生徒の名前をアルファベット順に保存しています。

HashMapの内容を表示

printHashMap(studentHashMap);

このメソッドではHashMapに格納されている名前と点数を入力された順番に表示します。

HashMapは順序を保証しないため、出力される順序は予測できません。

TreeMapの内容を表示

printTreeMap(studentTreeMap);

このメソッドではTreeMapに格納されているデータをキー(名前)のアルファベット順に表示します。

TreeMapは常にキーの自然順序でデータを並べ替えるため、名前がアルファベット順で表示されることが保証されます。

まとめ

このプログラムではHashMapTreeMapの違いを学びながら、生徒の名前と点数を格納し、それを入力順とアルファベット順で表示しています。

TreeMapを使うとデータをキーに基づいてソートすることができ、順序が重要な場面で非常に役立ちます。

<<前の問題 問題集Top 次の問題>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    JAVAテキスト&問題集へ戻る
    トップページへ戻る