TreeMap
是 Java 中的一个有序映射实现,它基于红黑树数据结构来存储键值对,并且可以根据键的自然顺序或者自定义的比较器来进行排序。下面是关于 TreeMap
的基本介绍、细节讨论、使用注意事项、常用方法以及一些底层实现细节。
基本介绍:
TreeMap
是Map
接口的实现类,它实现了一个有序的键值对集合。TreeMap
中的键是按照其自然顺序或者比较器的顺序进行排序的。TreeMap
不允许存储重复的键,每个键在映射中只能出现一次。
细节讨论:
TreeMap
会根据键的自然顺序或者自定义的比较器来进行排序。如果键没有实现Comparable
接口并且没有提供比较器,会在运行时抛出ClassCastException
。- 添加、删除和查找操作的时间复杂度平均为 O(log n),其中 n 是映射中键值对的数量。
TreeMap
不是线程安全的,如果在多线程环境下使用,需要进行适当的同步控制。
使用注意事项:
- 在使用
TreeMap
时,键需要具有可比较性(可以用instanceOf作为防护机制),要么实现Comparable
接口,要么在构造TreeMap
时提供一个比较器。 - 自然顺序是指键的默认顺序,如数字的升序、字符串的字典序等。如果需要不同的顺序,可以通过比较器来实现。
常用方法:
put(K key, V value)
: 向映射中添加一个键值对。get(Object key)
: 获取指定键对应的值。remove(Object key)
: 从映射中移除指定的键值对。containsKey(Object key)
: 判断映射是否包含指定的键。isEmpty()
: 判断映射是否为空。size()
: 返回映射中键值对的数量。clear()
: 清空映射中的所有键值对。
底层源码和底层实现:
TreeMap
的底层基于红黑树(Red-Black Tree)数据结构来存储键值对。红黑树是一种自平衡的二叉查找树,确保树的高度始终保持在一个相对较小的范围内,从而保证了添加、删除和查找操作的高效性能。- 红黑树的特性使得键在树中按照顺序排列,从而实现了
TreeMap
的有序性。 - 通过自平衡的操作,红黑树能够在插入和删除键值对时自动进行树的重新平衡,从而保持树的结构稳定。
总之,TreeMap
提供了一个有序的键值对映射实现,通过底层的红黑树数据结构实现了高效的键值对存储、添加、删除和查找操作。在需要保持键的顺序的映射场景下,可以使用 TreeMap
。
TreeMap的底层代码分析:
public class TreeMap_ {
public static void main(String[] args) {
//使用默认的构造器,创建 TreeMap, 默认是按自然顺序排序的(升序)
/*
要求:按照传入的 k(String) 的长度进行排序
*/
// TreeMap treeMap = new TreeMap();//默认排序
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//按照传入的 k(String) 的大小进行排序
//按照 K(String) 的长度大小排序
//return ((String) o2).compareTo((String) o1);
return ((String) o2).length() - ((String) o1).length();
}
});
treeMap.put("ret1", "JACK");
treeMap.put("tom", "TOM");
treeMap.put("a", "A");
treeMap.put("ret", "RET");//加入不了,因为此时是按字符串的长度来排序的,长度和tom相同都为3,但若是在自然排序下是可以插入进去的,因为默认的情况下是比较的两个字符串是否一样而不是比较的长度
System.out.println("treemap=" + treeMap);
/*
源码分析:
1. 构造器.把传入的实现了Comparator 接口的匿名内部类(对象),传给给 TreeMap 的 comparator
public TreeMap(Comparator < ? super K > comparator) {
this.comparator = comparator;
}
2. 调用 put 方法
2.1 第一次添加, 把 k - v 封装到 Entry 对象,放入 root
Entry<K, V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
2.2 以后添加
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do { //遍历所有的 key , 给当前 key 找到适当位置
parent = t;
cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类的 compare
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else //如果遍历过程中,发现准备添加 Key 和当前已有的 Key 相等,就不添加
return t.setValue(value);
} while (t != null);
}
*/
}
}