TreeMap原理实现及常用方法(2)

我们来分析一下源码

public V put(K key, V value) { Entry<K,V> t = root; /** * 如果根节点都为null,还没建立起来红黑树,我们先new Entry并赋值给root把红黑树建立起来,这个时候红 * 黑树中已经有一个节点了,同时修改操作+1。 */ if (t == null) { compare(key, key); root = new Entry<>(key, value, null); size = 1; modCount++; return null; } /** * 如果节点不为null,定义一个cmp,这个变量用来进行二分查找时的比较;定义parent,是new Entry时必须 * 要的参数 */ int cmp; Entry<K,V> parent; // cpr表示有无自己定义的排序规则,分两种情况遍历执行 Comparator<? super K> cpr = comparator; if (cpr != null) { /** * 从root节点开始遍历,通过二分查找逐步向下找 * 第一次循环:从根节点开始,这个时候parent就是根节点,然后通过自定义的排序算法 * cpr.compare(key, t.key)比较传入的key和根节点的key值,如果传入的key<root.key,那么 * 继续在root的左子树中找,从root的左孩子节点(root.left)开始:如果传入的key>root.key, * 那么继续在root的右子树中找,从root的右孩子节点(root.right)开始;如果恰好key==root.key, * 那么直接根据root节点的value值即可。 * 后面的循环规则一样,当遍历到的当前节点作为起始节点,逐步往下找 * * 需要注意的是:这里并没有对key是否为null进行判断,建议自己的实现Comparator时应该要考虑在内 */ 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 { //从这里看出,当默认排序时,key值是不能为null的 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); } /** * 能执行到这里,说明前面并没有找到相同的key,节点已经遍历到最后了,我们只需要new一个Entry放到 * parent下面即可,但放到左子节点上还是右子节点上,就需要按照红黑树的规则来。 */ Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; /** * 节点加进去了,并不算完,我们在前面红黑树原理章节提到过,一般情况下加入节点都会对红黑树的结构造成 * 破坏,我们需要通过一些操作来进行自动平衡处置,如【变色】【左旋】【右旋】 */ fixAfterInsertion(e); size++; modCount++; return null; }

put方法源码中通过fixAfterInsertion(e)方法来进行自平衡处理,我们回顾一下插入时自平衡调整的逻辑,下表中看不懂的名词可以参考关于红黑树(R-B tree)原理,看这篇如何

 无需调整【变色】即可实现平衡【旋转+变色】才可实现平衡
情况1:   当父节点为黑色时插入子节点   空树插入根节点,将根节点红色变为黑色   父节点为红色左节点,叔父节点为黑色,插入左子节点,那么通过【左左节点旋转】  
情况2:   -   父节点和叔父节点都为红色   父节点为红色左节点,叔父节点为黑色,插入右子节点,那么通过【左右节点旋转】  
情况3:   -   -   父节点为红色右节点,叔父节点为黑色,插入左子节点,那么通过【右左节点旋转】  
情况4:   -   -   父节点为红色右节点,叔父节点为黑色,插入右子节点,那么通过【右右节点旋转】  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/cc4283d0a1a10ea5fb552fbdb04fdcad.html