TreeMap是红黑二叉树的典型实现。我们打开TreeMap的源码,发现里面有一行核心代码:
root用来存储整个树的根节点。我们继续跟踪Entry(是TreeMap的内部类)的代码:
可以看到里面存储了本身数据、左节点、右节点、父节点、以及节点颜色。 TreeMap的put()/remove()方法大量使用了红黑树的理论。
TreeMap和HashMap用法大致相同,不同点是TreeMap可以用来排序。
HashMap和TreeMap比较:
-
HashMap是Key无序的(key可以为null),而TreeMap是Key有序的(key不能为null)。
-
效率高于,在需要排序的时才选用。
- TreeMap 默认排序
对于简单的数字、英文字母等类型,按照key的字典顺序来排序(升序)。
【示例】TreeMap 默认排序
// 创建一个TreeMap对象
TreeMap<String, Integer> map = new TreeMap<String, Integer>();
// 添加键值对
map.put("e", 55);
map.put("a", 11);
map.put("d", 44);
map.put("c", 33);
map.put("d", 44); // 只能输出一个
map.put("b", 22);
// 遍历输出map中的键和值
Set<Entry<String, Integer>> entrySet = map.entrySet();
Iterator<Entry<String, Integer>> iterator = entrySet.iterator();
while(iterator.hasNext()) {
Entry<String, Integer> next = iterator.next();
System.out.println("key:" + next.getKey() + " value:" + next.getValue());
}
默认排序输出结果如下(map中的key不能重复):
key:a value:11
key:b value:22
key:c value:33
key:d value:44
key:e value:55
- Comparable****接口排序
为什么TreeMap对String类型的key值有排序效果呢?查看String类源码可知String类实现了Comparable接口,该接口中只有一个public int compareTo(String str);方法,对象的大小关系由返回值来确定,返回负整数,零,正整数表示当前对象小于,等于,大于指定对象。
因此如果想要对自定义的对象进行排序,那么我们可以让该类实现Comparable接口, 然后实现Comparable接口的compareTo方法。
【示例】创建自定义对象 Teacher
class Teacher implements Comparable<Teacher> {
String name;
int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Teacher o) {
if(this.age > o.age) {
return 1; // 返回正数表示:this大于o1。
}else if(this.age < o.age) {
return -1; // 返回负数表示:this小于o1。
}else {
return 0; // 返回零表示:this等于o1。
}
}
}
自定义排序输出结果如下(两个王五只输出一个):
name:赵六 age:18 value:南京
name:李四 age:20 value:北京
name:王五 age:27 value:上海
name:刘七 age:29 value:深圳
name:张三 age:38 value:武汉
- Comparator****接口排序
要想改变TreeMap的默认比较次序,我们还可以在其构造函数中传入一个自己的比较器。TreeMap的比较器构造函数如下:
Comparator可以对key的对象进行排序的比较器接口,实现该接口的public compare(T o1,To2)方法即可实现排序,返回的int值的正负表示两值的大小。
【示例】使用Comparator实现升序排序
public static void main(String[] args) {
// 创建一个TreeMap对象
TreeMap<Student, String> map = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if(o1.age > o2.age) {
return 1;
}else if(o1.age < o2.age) {
return -1;
}else {
return 0;
}
}
});
// 添加键值对
map.put(new Student("张三", 38), "武汉");
map.put(new Student("李四", 20), "北京");
map.put(new Student("王五", 27), "上海");
map.put(new Student("赵六", 18), "南京");
map.put(new Student("王五", 27), "上海"); // 只能输出一个“王五”
map.put(new Student("刘七", 29), "深圳");
// 遍历map
Set<Student> set = map.keySet();
Iterator<Student> iterator = set.iterator();
while(iterator.hasNext()) {
Student stu = iterator.next();
String key = map.get(value);
System.out.println("name:" + stu.name + " age:" + stu.age +" key:" + key);
}
}
自定义排序输出结果如下(两个王五只输出一个):
name:赵六 age:18 key:南京
name:李四 age:20 key:北京
name:王五 age:27 key:上海
name:刘七 age:29 key:深圳
name:张三 age:38 key:武汉
- 使用TreeMap要点:
-
由于是二叉树,需要对元素做内部排序。所以要么实现Comparable接口,要么实现Comparator接口,否则会抛出java.lang.ClassCastException异常。
-
TreeMap的key不能为null,否则抛出java.lang.NullPointerException异常。
ps:如需最新的免费文档资料和教学视频,请添加QQ群(627407545)领取。