Java中的TreeMap底层源码分析
一. 基本原理和优缺点
TreeMap与Hashmap、LinkedHashMap不同,他的底层不再是数组,而是一颗红黑树。
在插入、删除或者替换元素时,TreeMap能按照事先约定的顺序来对key进行排序和迭代查询。
支持二叉搜索,因此做查询操作时,时间复杂度是O(logn),虽然比起纯粹使用数组要慢O(1),但是比普通的链表要快O(n)。
插入数据类似链表,只调整几个指针就实现插入操作。
TreeMap的缺点在于,为了使用红黑树,每次新增、删除、修改一个节点后,都需要重新调整整颗树,达到红黑树的要求,这个调整的过程可能涉及到变色,也可能涉及到左旋、右旋,所以耗时啊!
二. 源码分析
2.1 put(K key, V value)
TreeMap<Integer, String> map = new TreeMap<>(); map.put(2, "张三"); map.put(1, "李四"); map.put(3, "王五"); map.put(4, "赵六");
Treemap默认使用key的升序排序,如果遍历上方的map,能获取到1->2->3->4排列顺序的key-value对。
我们也可以自定义比较key的方法,具体的做法如下:
Map<Integer, String> map = new TreeMap<Integer, String>(new Comparator<Integer> () { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }) {};
此时,再次遍历map,能获取到4->3->2->1排列顺序的key-value对。
我们可以把TreeMap put( )方法的源码分解成几个部分。
首先,判断当前TreeMap有没有节点,如果连一个节点都没有,那好办,就拿着本次待新增的k-v,做成一个节点,此时红黑树只有一个节点。
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; }
接着,将待插入的key与根节点对应的key进行比较,这里就可以自定义比较方式了。
Comparator<? super K> cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); }
上图中这么大一坨代码,无非就是列举了两种情况,如果没有显示的给出Comparator,则使用key的compareTo()方法比较大小。如果给出了显示的Comparator,则使用自定义的compare()方法进行比较。
然后,把较小的节点挂到根节点的左边,把较大的节点挂到根节点的右边。这不就是二叉搜索树的概念么。
if (cmp < 0) parent.left = e; else parent.right = e;
最后,使用红黑树相关的算法,利用变色啊、旋转啊等手段,使添加了节点的二叉搜索树重新成为红黑树。
fixAfterInsertion(e);
2.2 红黑树节点的结构
K key; V value; Entry<K,V> left; Entry<K,V> right; Entry<K,V> parent; boolean color = BLACK;
到此这篇关于Java中的TreeMap底层源码分析的文章就介绍到这了,更多相关TreeMap源码分析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Springboot使用redis进行api防刷限流过程详解
这篇文章主要介绍了Springboot使用redis进行api防刷限流过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2019-12-12IDEA连接MySQL提示serverTimezone的问题及解决方法
很多朋友私聊小编,使用IDEA软件连接MySQL数据库时总是提示Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.的错误,小编就不一一回复大家了,下面小编把我的解决方法分享到脚本之家平台,需要的朋友参考下吧2021-05-05java连接池Druid获取连接getConnection示例详解
这篇文章主要为大家介绍了java连接池Druid获取连接getConnection示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-09-09SpringBoot中fastjson自定义序列化和反序列化的实战分享
在fastjson库中,为了提供灵活的序列化和反序列化机制,设计了一系列的扩展点,以下是在SpringBoot和SpringClould环境中对这些扩展点的详细介绍及其实战使用,通过代码示例讲解的非常详细,需要的朋友可以参考下2024-07-07
最新评论