Java 逆引き集 | NavigableMap / NavigableSet(近傍検索) — 前後関係の取得

Java Java
スポンサーリンク

NavigableMap / NavigableSet(近傍検索) — 前後関係の取得

NavigableMapNavigableSet は、ソート済みのデータ構造に「近傍検索(前後関係の取得)」を追加したインターフェースです。
初心者が理解すべきポイントは「ソート順を保ちながら、指定したキーや要素の前後を簡単に探せる」ということです。


特徴

  • NavigableMap: ソート済みの Map。代表的な実装は TreeMap
  • NavigableSet: ソート済みの Set。代表的な実装は TreeSet
  • 近傍検索メソッド: lower, floor, ceiling, higher などで「指定値の前後」を取得できる。
  • 範囲ビュー: subMap, headMap, tailMap で部分範囲を切り出せる。

👉 「順序付きデータ」+「近傍検索」が必要な場面に最適。


基本コード例(NavigableMap)

import java.util.*;

public class NavigableMapDemo {
    public static void main(String[] args) {
        NavigableMap<Integer, String> map = new TreeMap<>();
        map.put(10, "Ten");
        map.put(20, "Twenty");
        map.put(30, "Thirty");
        map.put(40, "Forty");

        System.out.println(map.floorEntry(25));   // 20=Twenty(25以下の最大キー)
        System.out.println(map.ceilingEntry(25)); // 30=Thirty(25以上の最小キー)
        System.out.println(map.lowerEntry(20));   // 10=Ten(20より小さい最大キー)
        System.out.println(map.higherEntry(20));  // 30=Thirty(20より大きい最小キー)
    }
}
Java

基本コード例(NavigableSet)

import java.util.*;

public class NavigableSetDemo {
    public static void main(String[] args) {
        NavigableSet<Integer> set = new TreeSet<>();
        set.addAll(List.of(10, 20, 30, 40));

        System.out.println(set.floor(25));   // 20(25以下の最大要素)
        System.out.println(set.ceiling(25)); // 30(25以上の最小要素)
        System.out.println(set.lower(20));   // 10(20より小さい最大要素)
        System.out.println(set.higher(20));  // 30(20より大きい最小要素)
    }
}
Java

近傍検索メソッドまとめ

メソッド意味(Mapの場合は Entry、Setの場合は要素)
lower(x)x より 小さい最大
floor(x)x 以下の最大
ceiling(x)x 以上の最小
higher(x)x より 大きい最小

👉 「より小さい」「以下」「以上」「より大きい」を区別して覚える。


例題で練習

例題1: 成績管理(点数の近傍検索)

NavigableMap<Integer, String> scores = new TreeMap<>();
scores.put(60, "Tanaka");
scores.put(70, "Sato");
scores.put(80, "Suzuki");
scores.put(90, "Kato");

System.out.println(scores.floorEntry(75));   // 70=Sato(75以下の最大)
System.out.println(scores.ceilingEntry(75)); // 80=Suzuki(75以上の最小)
Java

例題2: 日付ごとのイベント管理

NavigableMap<String, String> events = new TreeMap<>();
events.put("2025-12-01", "Meeting");
events.put("2025-12-05", "Workshop");
events.put("2025-12-10", "Conference");

System.out.println(events.lowerEntry("2025-12-07"));   // 2025-12-05=Workshop
System.out.println(events.higherEntry("2025-12-07"));  // 2025-12-10=Conference
Java

例題3: NavigableSet で範囲検索

NavigableSet<Integer> nums = new TreeSet<>(List.of(10, 20, 30, 40, 50));

System.out.println(nums.subSet(20, true, 40, true)); // [20, 30, 40]
System.out.println(nums.headSet(30, false));         // [10, 20]
System.out.println(nums.tailSet(30, true));          // [30, 40, 50]
Java

テンプレート集

NavigableMap の宣言

NavigableMap<KeyType, ValueType> map = new TreeMap<>();
Java

NavigableSet の宣言

NavigableSet<Type> set = new TreeSet<>();
Java

近傍検索

map.floorEntry(key);
map.ceilingEntry(key);
map.lowerEntry(key);
map.higherEntry(key);

set.floor(value);
set.ceiling(value);
set.lower(value);
set.higher(value);
Java

範囲ビュー

map.subMap(fromKey, true, toKey, false);
set.subSet(fromVal, true, toVal, true);
Java

実務でのコツ

  • 範囲検索: 日付や数値の範囲検索に便利。
  • 近傍検索: 「直前」「直後」のデータを効率的に取得できる。
  • 順序付きデータ: TreeMap/TreeSet は常にソート済みなので、ランキングや時系列管理に最適。
  • スレッド安全: TreeMap/TreeSet は非同期。並行環境では ConcurrentSkipListMap / ConcurrentSkipListSet を検討。

まとめ

  • NavigableMap / NavigableSet は「ソート+近傍検索」ができるコレクション。
  • lower/floor/ceiling/higher を使えば前後関係を簡単に取得可能。
  • 範囲ビューで部分集合を扱える。

👉 練習課題として「TreeMap に日付をキーとしてイベントを登録し、指定日付の直前・直後のイベントを検索する」プログラムを書いてみると、NavigableMap の便利さが体感できます。

タイトルとURLをコピーしました