HashMap 雖高效但無序,TreeMap 基於紅黑樹實現鍵的自然順序或定制順序,並實現 SortedMap、NavigableMap 接口,提供豐富的區間查詢、鄰近鍵搜索能力。本文從基本用法、高級導航 API、紅黑樹核心源碼、特點對比四個維度深度解析。
// 1. 自然順序:鍵必須實現 Comparable
new TreeMap<>();
// 2. 定制順序:傳入 Comparator,鍵無需實現 Comparable
new TreeMap<>(Comparator comparator);
選型原則:自然順序簡單直接;定制順序靈活解耦,支持多維度排序(如忽略大小寫、逆序、複合鍵)。
// 忽略大小寫
new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
// 逆序
new TreeMap<>(Collections.reverseOrder());
// 逆序 + 忽略大小寫
new TreeMap<>(Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
// 自定義:字符串日期按時間排序
new TreeMap<>(new Comparator() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public int compare(String o1, String o2) {
try { return sdf.parse(o1).compareTo(sdf.parse(o2)); }
catch (ParseException e) { return 0; }
}
});
TreeMap map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
map.put("T", "tree");
map.put("t", "try"); // 比較器認為 "T" == "t"
// 結果:只有 "T=try",鍵保留首次,值覆蓋為最後一次
TreeMap 實現鏈:Map → SortedMap → NavigableMap
| 方法 | 說明 |
|---|---|
comparator() | 返回比較器,自然順序返回 null |
firstKey() / lastKey() | 首尾鍵 |
headMap(K toKey) | 鍵 < toKey 的子映射視圖 |
tailMap(K fromKey) | 鍵 >= fromKey 的子映射視圖 |
subMap(K fromKey, K toKey) | 鍵 ∈ [fromKey, toKey) 的子映射視圖 |
| 方法 | 語義 | 對比 SortedMap |
|---|---|---|
floorKey/Entry(K key) | ≤ key 的最大鍵/項 | 更精準的 floor 操作 |
lowerKey/Entry(K key) | < key 的最大鍵/項 | 嚴格小於 |
ceilingKey/Entry(K key) | >= key 的最小鍵/項 | 更精準的 ceiling 操作 |
higherKey/Entry(K key) | > key 的最小鍵/項 | 嚴格大於 |
pollFirstEntry() / pollLastEntry() | 移除並返回首/尾項 | 支持隊列式消費 |
descendingMap() / descendingKeySet() | 逆序視圖 | 無需構造新對象 |
headMap(toKey, inclusive) | 可控制是否包含邊界 | 解決邊界歧義 |
NavigableMap map = new TreeMap<>();
map.put("a", "abstract"); map.put("f", "final"); map.put("c", "call");
map.firstEntry(); // a=abstract
map.lastEntry(); // f=final
map.floorEntry("d"); // c=call (≤d 最大)
map.ceilingEntry("d"); // f=final (≥d 最小)
map.descendingMap().subMap("d", false, "a", true); // {c=call, a=abstract} 逆序區間
Entry
static final class Entry implements Map.Entry {
K key; V value;
Entry left, right, parent;
boolean color = BLACK; // 紅黑樹顏色
Entry(K key, V value, Entry parent) { ... }
}
public V put(K key, V value) {
Entry t = root;
if (t == null) { // 首節點
compare(key, key); // 類型/空檢查
root = new Entry<>(key, value, null);
size = 1; modCount++; return null;
}
// 尋找插入位置
Comparator super K> cpr = comparator;
Entry parent;
int cmp;
if (cpr != null) { // 定制比較器路徑
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0) t = t.left;
else if (cmp > 0) t = t.right;
else return t.setValue(value); // 鍵已存在,覆蓋值
} while (t != null);
} else { // 自然順序路徑
if (key == null) throw new NullPointerException();
Comparable super K> k = (Comparable super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0) t = t.left;
else if (cmp > 0) t = t.right;
else return t.setValue(value);
} while (t != null);
}
// 插入新節點
Entry e = new Entry<>(key, value, parent);
if (cmp < 0) parent.left = e; else parent.right = e;
fixAfterInsertion(e); // 關鍵:紅黑樹旋轉+變色,保持平衡
size++; modCount++;
return null;
}
final Entry getEntry(Object key) {
if (comparator != null) return getEntryUsingComparator(key);
if (key == null) throw new NullPointerException();
Comparable super K> k = (Comparable super K>) key;
Entry p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0) p = p.left;
else if (cmp > 0) p = p.right;
else return p;
}
return null;
}
deleteEntry:三種情況統一轉換successor(p),複製其鍵值到當前節點,轉為刪除後繼節點(後繼最多一子);fixAfterDeletion(replacement);fixAfterDeletion(p)。successor() 實現:有右子樹 → 右子樹最左節點;無右子樹 → 向上找首個作為左孩子的祖先。
final Entry getFirstEntry() { // 最左節點
Entry p = root;
if (p != null) while (p.left != null) p = p.left;
return p;
}
static Entry successor(Entry t) { // 後繼邏輯同上 }
| 維度 | HashMap | TreeMap |
|---|---|---|
| 底層結構 | 數組+鏈表/紅黑樹 (JDK8) | 紅黑樹 |
| 鍵順序 | 無序 | 有序 (自然/定制) |
| 鍵要求 | 正確重寫 hashCode/equals | 實現 Comparable 或提供 Comparator |
| Null 鍵 | 允許一個 null key | 自然順序不允許;定制比較器視實現而定 |
| 查找/插入/刪除 | O(1) 平均 | O(log n) 保證 |
| 適用場景 | 高頻增刪改查、無序需求 | 範圍查詢、排序輸出、鄰近搜索、優先級隊列 |
TreeMap 以紅黑樹為骨架,實現了有序映射與導航查詢的完美平衡。理解其比較器策略、旋轉修復邏輯、子映射視圖機制,是掌握 Java 集合框架進階能力的關鍵一環。
延伸學習:
🔹 TreeSet:基於 TreeMap 實現的有序集合;
🔹 ConcurrentSkipListMap:無鎖併發有序映射,基於跳表;
🔹 B+ 樹在數據庫索引中的應用,對比紅黑樹在內存場景的優勢。