TreeMap 核心知识点与面试题解析
一、TreeMap 基础概念
TreeMap
是 Java 集合框架中基于 红黑树(Red-Black Tree) 实现的 Map
,具有以下特点:
-
有序性 :默认按 key 的自然顺序 (
Comparable
)或自定义顺序 (Comparator
)排序。 -
时间复杂度:
-
插入、删除、查找:O(log n)
-
遍历(如
entrySet()
):O(n)(中序遍历)
-
-
线程不安全 :需用
Collections.synchronizedMap()
或ConcurrentSkipListMap
替代。
二、TreeMap 核心实现
1. 底层数据结构:红黑树
-
红黑树特性:
-
每个节点是红色或黑色。
-
根节点和叶子节点(NIL)是黑色。
-
红色节点的子节点必须是黑色(不能连续红节点)。
-
从任意节点到其叶子节点的路径上,黑色节点数相同(黑高平衡)。
-
-
自平衡机制 :通过旋转(左旋/右旋)和变色保持平衡。
2. 排序方式
-
自然排序 (
Comparable
):java
javaTreeMap<String, Integer> map = new TreeMap<>(); // 默认按 String 字典序
自定义排序 (
Comparator
): -
java
java
TreeMap<Integer, String> map = new TreeMap<>((a, b) -> b - a); // 降序
三、高频面试题
1. TreeMap 和 HashMap 的区别?
对比项 | TreeMap | HashMap |
---|---|---|
底层结构 | 红黑树 | 数组 + 链表/红黑树 |
是否有序 | 是(按 key 排序) | 否(无序) |
时间复杂度 | O(log n) | O(1)(平均) |
线程安全 | 否 | 否 |
允许 null key | 取决于 Comparator | 允许(但只能有一个) |
2. TreeMap 如何保证有序?
-
红黑树的中序遍历(左-根-右)会按 key 的顺序输出。
-
依赖
Comparable
或Comparator
定义排序规则。
3. TreeMap 的 put() 方法流程?
-
如果红黑树为空,直接插入为根节点(黑色)。
-
按 Comparator 或 Comparable 查找插入位置。
-
插入新节点(默认为红色)。
-
平衡调整(可能涉及变色和旋转):
-
如果父节点是红色:
-
检查叔叔节点:
-
叔叔是红色 → 变色(父、叔变黑,祖父变红)。
-
叔叔是黑色 → 旋转 + 变色(左旋/右旋)。
-
-
-
4. 如何实现自定义排序?
java
java
// 按 value 排序(需转为 List 再排序)
List<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet());
list.sort((a, b) -> a.getValue() - b.getValue());
// 或者使用 Comparator
TreeMap<String, Integer> customMap = new TreeMap<>((a, b) -> b.compareTo(a)); // 降序
5. TreeMap 的 ceilingKey() 和 floorKey() 方法作用?
-
ceilingKey(K key):返回 ≥ key 的最小 key(如没有,返回 null)。
-
floorKey(K key):返回 ≤ key 的最大 key(如没有,返回 null)。
java
java
TreeMap<Integer, String> map = new TreeMap<>();
map.put(1, "A");
map.put(3, "B");
map.put(5, "C");
map.ceilingKey(2); // 3
map.floorKey(4); // 3
6. TreeMap 为什么用红黑树而不用 AVL 树?
对比项 | 红黑树 | AVL 树 |
---|---|---|
平衡标准 | 黑高平衡(宽松) | 严格高度平衡(左右子树高度差 ≤1) |
插入/删除 | 最多 3 次旋转(O(1)) | 可能需 O(log n) 次旋转 |
查询效率 | O(log n),但常数项较大 | 更快(严格平衡) |
适用场景 | 适合频繁修改(如 Java 集合) | 适合高频查询(如数据库索引) |
四、代码实战
1. 按 key 降序排列
java
java
TreeMap<Integer, String> map = new TreeMap<>((a, b) -> b - a);
map.put(3, "C");
map.put(1, "A");
map.put(2, "B");
System.out.println(map); // {3=C, 2=B, 1=A}
2. 获取子映射(subMap)
java
java
TreeMap<Integer, String> map = new TreeMap<>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "D");
// 获取 [2, 4) 的子映射
SortedMap<Integer, String> subMap = map.subMap(2, 4);
System.out.println(subMap); // {2=B, 3=C}
五、总结
-
TreeMap 适用于需要有序 key 的场景(如范围查询、排序)。
-
底层是红黑树,保证 O(log n) 的操作效率。
-
面试重点:
-
红黑树原理
-
与 HashMap 的区别
-
排序方式(Comparable/Comparator)
-
常用方法(ceilingKey, floorKey, subMap)
-