TreeMap原理
TreeMap和HashMap有什么关系?
TreeMap与HashMap实现了同一个接口,所以TreeMap和HashMap在方法上相似之处,但TreeMap与HashMap底层原理和实现上没有任何关系。
HashMap拥有的方法TreeMap也有,还有一些TreeMap特有的方法(NavigableMap),后续介绍这些方法。
介绍
TreeMap是一个红黑树基于NavigableMap实现的,排序规则可在对象实现Comparatory
接口,也可以在创建TreeMap时自定义Comparatory
接口
构造方法创建
Map<K, V> map = new TreeMap<>();
// 注意不要用Map进行声明,这样会失去TreeMap特有的方法
TreeMap<K, V> map = new TreeMap<>();
// 正确方式
TreeMap<K, V> map = new TreeMap<>(Comparator<? super K> comparator);
// 创建,并自定义比较器排序
TreeMap<K, V> map = new TreeMap<>(Map<? extends K,? extends V> m);
// 创建,并复制Map以自然顺序进行排序
TreeMap<K, V> map = new TreeMap<>(SortedMap<K,? extends V> m);
// 创建,并复制map以相同的规则排序
自定义排序排序(降序排序)
构造器自定义
// 标准使用:Comparator
TreeMap<Integer, String> map = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
// 便捷使用:匿名方法
TreeMap<Integer, String> map = new TreeMap<>((o1, o2) -> o2-o1);
对象实现
class Student implements Comparable<Student> {
int id, age;
public Student(int id, int age) {
this.id = id;
this.age = age;
}
@Override
public int compareTo(Student o) {
return o.id - this.id;
}
}
// 用对象作为key时,在使用时需要用到compareTo里使用到的属性值作为排序与获取的规则
TreeMap<Student, String> map = new TreeMap<>();
map.put(new Student(1, 18), "张三");
map.put(new Student(2, 25), "李四");
map.put(new Student(3, 16), "王五");
map.put(new Student(3, 19), "赵六");
map.put(new Student(4, 25), "老王");
map.entrySet().forEach(System.out::println);
System.out.println("-------分隔符-------")
Map.Entry<Student, String> geMap = map.ceilingEntry(new Student(2, 9999));
System.out.println(geMap);
输出结果:
Student(id=4, age=25)=老王
Student(id=3, age=16)=赵六
Student(id=2, age=25)=李四
Student(id=1, age=18)=张三
-------分隔符-------
Student(id=2, age=25)=李四
方法介绍与使用
方法介绍
// 1.所有获取
NavigableSet<K> keySet(); // 返回正向输出所有的key
NavigableSet<K> descendingKeySet(); // 返回颠倒输出所有的key
NavigableMap<K, V> descendingMap(); // 返回颠倒TreeMap
// 2.比较获取单个数据
Map.Entry<K,V> firstEntry(); // 返回最小的map
Map.Entry<K,V> lastEntry(); // 返回最大的map
Map.Entry<K,V> ceilingEntry(K k); // 大于等于k的map
Map.Entry<K,V> higherEntry(K k); // 大于k的map
Map.Entry<K,V> floorEntry(K k); // 小于等于k的map
Map.Entry<K,V> lowerEntry(K k); // 小于k的map
K firstKey(K k); // 输出最大的key
K lastKey(K k); // 输出最小的key
K ceilingKey(K k); // 大于等于k的Key
K higherKey(K k); // 大于k的Key
K floorKey(K k); // 小于等于k的Key
K lowerKey(K k); // 小于k的key
// 3.比较获取多个数据
SortedMap<K,V> headMap(K k); // 小于k的所有map
SortedMap<K,V> headMap(K k, boolean i); // 小于等于k的所有map
SortedMap<K,V> tailMap(K k); // 大于等于k的所有map
SortedMap<K,V> subMap(K a, K b); // 范围在[a,b]的所有map
SortedMap<K,V> subMap(K a, boolean i, K b, boolean i); // 范围在[a,b)的所有map
// 4.弹出数据
Map.Entry<K,V> pollFirsttEntry(); // 弹出最大的map
Map.Entry<K,V> pollLastEntry(); // 弹出最小的map
方法使用
- 使用案例代码
TreeMap<Integer, String> map = new TreeMap<>();
map.put(5, "张三");
map.put(8, "李四");
map.put(2, "王五");
map.put(6, "赵六");
map.put(9, "小明");
map.put(5, "老王");
- 所有获取
Set<Integer> keySet = map.keySet();
System.out.println("正向输出所有的key:"+ keySet);
Set<Integer> descKeySet = map.descendingKeySet();
System.out.println("颠倒输出所有的key:" + descKeySet);
// 颠倒TreeMap,注意颠倒后的TreeMap和原有TreeMap是共享的
NavigableMap<Integer, String> map2 = map.descendingMap();
map2.put(1, "小红"); // 注意注释,防止影响后续代码的显示
System.out.println("正向上的TreeMap:");
map.entrySet().forEach(System.out::println);
System.out.println("颠倒后的TreeMap:");
map2.entrySet().forEach(System.out::println);
输出结果:
正向输出所有的key:[2, 5, 6, 8, 9]
颠倒输出所有的key:[9, 8, 6, 5, 2]
正向上的TreeMap:
1=小红、2=王五、5=老王、6=赵六、8=李四、9=小明、
颠倒后的TreeMap:
9=小明、8=李四、6=赵六、5=老王、2=王五、1=小红、
- 比较获取单个数据
System.out.println("获取map数据:");
Map.Entry<Integer, String> minMap = map.firstEntry();
System.out.println("最小的map:" + minMap);
Map.Entry<Integer, String> maxMap = map.lastEntry();
System.out.println("最大的map:" + maxMap);
Map.Entry<Integer, String> geMap = map.ceilingEntry(6);
System.out.println("大于等于k的map:" + geMap);
Map.Entry<Integer, String> gtMap = map.higherEntry(6);
System.out.println("大于k的map:" + gtMap);
Map.Entry<Integer, String> leMap = map.floorEntry(6);
System.out.println("小于等于k的map:" + leMap);
Map.Entry<Integer, String> ltMap = map.lowerEntry(6);
System.out.println("小于k的map:" + ltMap);
System.out.println("-------分隔符-------");
System.out.println("只获取key:");
System.out.println("最大的key:" + map.firstKey());
System.out.println("最小的key:" + map.lastKey());
System.out.println("大于等于k的key:" + map.ceilingKey(6));
System.out.println("大于k的key:" + map.higherKey(6));
System.out.println("小于等于k的key:" + map.floorKey(6));
System.out.println("小于的key:" + map.lowerKey(6));
输出结果:
获取map数据:
最小的map:2=王五
最大的map:9=小明
大于等于k的map:6=赵六
大于k的map:8=李四
小于等于k的map:6=赵六
小于k的map:5=老王
-------分隔符-------
只获取key
最大的key:2
最小的key:9
大于等于k的key:6
大于k的key:8
小于等于k的key:6
小于的key:5
- 比较获取多个数据
SortedMap<Integer, String> ltSet = map.headMap(6);
System.out.print("输出小于6的所有map:");
ltSet.forEach((k,v)->System.out.print(k+"="+v+"、"));
SortedMap<Integer, String> leSet = map.headMap(6, true);
System.out.print("\n输出小于等于6的所有map:");
leSet.forEach((k,v)->System.out.print(k+"="+v+"、"));
SortedMap<Integer, String> maxSet = map.tailMap(6);
System.out.print("\n输出大于等于6的所有map:");
maxSet.forEach((k,v)->System.out.print(k+"="+v+"、"));
// []表示包含区间,()表示不包含区间
SortedMap<Integer, String> rangesMap = map.subMap(2, 8);
System.out.print("\n输出[x,y]范围的所有map:");
rangesMap.forEach((k,v)->System.out.print(k+"="+v+"、"));
SortedMap<Integer, String> rangeMap = map.subMap(2, true, 8, true);
System.out.print("\n输出[2, 8)范围的所有map:");
rangeMap.forEach((k,v)->System.out.print(k+"="+v+"、"));
输出结果:
输出小于6的所有map:2=王五、5=老王、
输出小于等于6的所有map:2=王五、5=老王、6=赵六、
输出大于等于6的所有map:6=赵六、8=李四、9=小明、
输出[x,y]范围的所有map:2=王五、5=老王、6=赵六、
输出[2, 8)范围的所有map:2=王五、5=老王、6=赵六、8=李四、
- 弹出数据
System.out.println("原数据:");
map.forEach((k, v) -> System.out.print(k + "=" + v + "、"));
Map.Entry<Integer, String> minMap = map.pollFirstEntry(); // 弹出最大的map
Map.Entry<Integer, String> maxMap = map.pollLastEntry(); // 弹出最小的map
System.out.println("\n输出弹出数据:");
System.out.println(minMap + " " + maxMap);
System.out.println("弹出后的数据:");
map.forEach((k, v) -> System.out.print(k + "=" + v + "、"));
输出结果:
原数据:
2=王五、5=老王、6=赵六、8=李四、9=小明、
输出弹出数据:
2=王五 9=小明
弹出后的数据:
5=老王、6=赵六、8=李四、