java版地图源码_TreeMap就这么简单【源码剖析】

前言

声明,本文用得是jdk1.8

前面章节回顾:

本篇主要讲解TreeMap~

看这篇文章之前最好是有点数据结构的基础:

当然了,如果讲得有错的地方还请大家多多包涵并不吝在评论去指正~

一、TreeMap剖析

按照惯例,我简单翻译了一下顶部的注释(我英文水平渣,如果有错的地方请多多包涵~欢迎在评论区下指正)

acf387568aaca520b20db7fb04f7ccc7.png

接着我们来看看类继承图:

d0a002ab4784451a927762a1ad6742d1.png

在注释中提到的要点,我来总结一下:

TreeMap实现了NavigableMap接口,而NavigableMap接口继承着SortedMap接口,致使我们的TreeMap是有序的!

TreeMap底层是红黑树,它方法的时间复杂度都不会太高:log(n)~

非同步

使用Comparator或者Comparable来比较key是否相等与排序的问题~

对我而言,Comparator和Comparable我都忘得差不多了~~~下面就开始看TreeMap的源码来看看它是怎么实现的,并且回顾一下Comparator和Comparable的用法吧!

1.1TreeMap的域

12f8edb6b6850351786af393db8e613c.png

1.2TreeMap构造方法

TreeMap的构造方法有4个:

14245411211bb78d2a6b34874012d423.png

可以发现,TreeMap的构造方法大多数与comparator有关:

f599e1c9d2ba6242271560959119631d.png

也就是顶部注释说的:TreeMap有序是通过Comparator来进行比较的,如果comparator为null,那么就使用自然顺序~

打个比方:

如果value是整数,自然顺序指的就是我们平常排序的顺序(1,2,3,4,5..)~

TreeMap treeMap = new TreeMap<>();

treeMap.put(1, 5);

treeMap.put(2, 4);

treeMap.put(3, 3);

treeMap.put(4, 2);

treeMap.put(5, 1);

for (Entry entry : treeMap.entrySet()) {

String s = entry.getKey() +"关注公众号:Java3y---->" + entry.getValue();

System.out.println(s);

}

2641979a0965a02306da7369ce3f0f29.png

1.3put方法

我们来看看TreeMap的核心put方法,阅读它就可以获取不少关于TreeMap特性的东西了~

14824559140ef7fb1cd0846591154bc1.png

下面是compare(Object k1, Object k2)方法

/**

* Compares two keys using the correct comparison method for this TreeMap.

*/

@SuppressWarnings("unchecked")

final int compare(Object k1, Object k2) {

return comparator==null ? ((Comparable super K>)k1).compareTo((K)k2)

: comparator.compare((K)k1, (K)k2);

}

如果我们设置key为null,会抛出异常的,就不执行下面的代码了。

438016145e3b8644ae9371de5f332b2e.png

1.4get方法

接下来我们来看看get方法的实现:

b984ce5eb19659198740fb596b8748c5.png

点进去getEntry()看看实现:

7ebaafa35cd4af2cda9d6dde0d5c4c21.png

如果Comparator不为null,接下来我们进去看看getEntryUsingComparator(Object key),是怎么实现的

b7f59315d65269c2537bece8893de4bf.png

1.5remove方法

9182a4b0d4be08136ce916c9c7d51d32.png

删除节点的时候调用的是deleteEntry(Entry p)方法,这个方法主要是删除节点并且平衡红黑树

平衡红黑树的代码是比较复杂的,我就不说了,你们去看吧(反正我看不懂)....

1.6遍历方法

在看源码的时候可能不知道哪个是核心的遍历方法,因为Iterator有非常非常多~

e992e1491139ebe0e6242c931a73d89f.png

此时,我们只需要debug一下看看,跟下去就好!

cb710817a65cbd145be92556284dafd4.png

dd86952020a700230383683abc82cf17.png

于是乎,我们可以找到:TreeMap遍历是使用EntryIterator这个内部类的

首先来看看EntryIterator的类结构图吧:

0c7cf85fca92d3c85f126ecee6b4f4ad.png

可以发现,EntryIterator大多的实现都是在父类中:

d0e16866c9bdf0c583a4285c57e66a83.png

那接下来我们去看看PrivateEntryIterator比较重要的方法:

89113c47cb2b3707f39041c9829055a4.png

我们进去successor(e)方法看看实现:

successor 其实就是一个结点的 下一个结点,所谓 下一个,是按次序排序后的下一个结点。从代码中可以看出,如果右子树不为空,就返回右子树中最小结点。如果右子树为空,就要向上回溯了。在这种情况下,t 是以其为根的树的最后一个结点。如果它是其父结点的左孩子,那么父结点就是它的下一个结点,否则,t 就是以其父结点为根的树的最后一个结点,需要再次向上回溯。一直到 ch 是 p 的左孩子为止。

ad22c0d349c7f59a7cc7d227dfbad287.png

二、总结

TreeMap底层是红黑树,能够实现该Map集合有序~

如果在构造方法中传递了Comparator对象,那么就会以Comparator对象的方法进行比较。否则,则使用Comparable的compareTo(T o)方法来比较。

值得说明的是:如果使用的是compareTo(T o)方法来比较,key一定是不能为null,并且得实现了Comparable接口的。

即使是传入了Comparator对象,不用compareTo(T o)方法来比较,key也是不能为null的

public static void main(String[] args) {

TreeMap map = new TreeMap((o1, o2) -> {

//主要条件

int num = o1.getAge() - o2.getAge();

//次要条件

int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;

return num2;

});

//创建学生对象

Student s1 = new Student("潘安", 30);

Student s2 = new Student("柳下惠", 35);

//添加元素进集合

map.put(s1, "宋朝");

map.put(s2, "元朝");

map.put(null, "汉朝");

//获取key集合

Set set = map.keySet();

//遍历key集合

for (Student student : set) {

String value = map.get(student);

System.out.println(student + "---------" + value);

}

}

96e4144ad0f3748c1cb281d8f482bc71.png

我们从源码中的很多地方中发现:Comparator和Comparable出现的频率是很高的,因为TreeMap实现有序要么就是外界传递进来Comparator对象,要么就使用默认key的Comparable接口(实现自然排序)

最后我就来总结一下TreeMap要点吧:

由于底层是红黑树,那么时间复杂度可以保证为log(n)

key不能为null,为null为抛出NullPointException的

想要自定义比较,在构造方法中传入Comparator对象,否则使用key的自然排序来进行比较

TreeMap非同步的,想要同步可以使用Collections来进行封装

参考资料:

1c63779741753a7d372ea17b32d74189.png

明天要是无意外的话,可能会写ConcurrentHashMap集合,敬请期待哦~~~~

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值