HashMap中的红黑树实现原理

爱⌒轻易说出口 提交于 2020-02-12 14:32:09

1.为什么要引入红黑树?

在jdk1.8引入了红黑树的设计,当冲突的链表长度超过8个时,链表结构就会转为红黑树结构,这样做的好处是避免在极端条件的情况下冲突链表过长而导致查询效率非常慢。
在这里插入图片描述

  • 红黑树查询:其访问性能近似于折半查找,时间复杂度O(logn);
  • 链表查询:这种情况下,需要遍历全部元素才行,时间复杂度O(n);

2.红黑树的简单概念

  • 红黑树是一种近似平衡的二叉查找树,其主要的优点就是平衡,即左右子树高度几乎一致,以此来防止树退化为链表,通过这种方式来保障查找的时间复杂度为log(n);
    在这里插入图片描述红黑树的基本特性
  • 1.每个节点要么是黑色,要么是红色,但根节点必须是黑色的;
  • 2.每个红色节点的两个子节点必须是黑色的;
  • 3.红色节点不能连续(即红色节点的孩子和父亲都不能是红色的);
  • 4.从任意节点到其子树中每个叶子结点的路径都包含相同数量的黑色节点;
  • 5.所有的叶子节点都是黑色的。
  • 6.新加入到红黑树的节点为红色节点。
    在树的结构发生改变时,往往会破坏条件3,4,需要通过调整使得查找树重新满足红黑树的条件。

3.红黑树的调整方式

调整可以分为两类:一类是颜色调整,即改变某个节点的颜色,这种比较简单,直接将节点颜色进行转换即可;另一类是结构调整,改变检索树的结构关系。结构调整主要包含两个基本操作:左旋(Rotate Left),右旋(Rotate Right)。

  • 1.左旋
    左旋的过程是将p的右子树绕p逆时针旋转,使得p的右子树成为p的父亲,同时修改相关节点的引用,使得左子树的深度加1,右子树的深度减1,通过这种做法来调整树的稳定性。过程如下:
    在这里插入图片描述在jdk1.8HashMap的源码中,红黑树内部类TreeNode属性分析。
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> { 		//指向父节点的指针 		TreeNode<K,V> parent; 
		//指向左孩子的指针 TreeNode<K,V> left; 
		//指向右孩子的指针 TreeNode<K,V> right;
		//前驱指针,跟next属性相反的指向 TreeNode<K,V> prev; 	
		//是否为红色节点 boolean red; 		
		...... }
//左旋方法如下
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
                                              TreeNode<K,V> p) {
            TreeNode<K,V> r, pp, rl;//p表示要调整的节点,r表示右节点,pp表示p的parent节点,rl表示p的右孩子的左孩子节点
            //r判断,如果r为空则旋转没有意义
            if (p != null && (r = p.right) != null) {
            	//设置rl的父亲为p
                if ((rl = p.right = r.left) != null)
                    rl.parent = p;
                //判断p的父亲,为空,为根节点,根节点的话就设置为黑色    
                if ((pp = r.parent = p.parent) == null)
                    (root = r).red = false;
                //判断p节点是左儿子还是右儿子    
                else if (pp.left == p)
                    pp.left = r;
                else
                    pp.right = r;
                r.left = p;
                p.parent = r;
            }
            return root;
        }
  • 右旋
 static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
                                               TreeNode<K,V> p) {
            TreeNode<K,V> l, pp, lr;//lr表示p的左孩子的右孩子
            //l判断,如果l为空则旋转没有意义
            if (p != null && (l = p.left) != null) {
            	//设置lr的父亲为p
                if ((lr = p.left = l.right) != null)
                    lr.parent = p;
                //判断p的父亲,为空,为根节点。根节点的话就设置为黑色    
                if ((pp = l.parent = p.parent) == null)
                    (root = l).red = false;
                //判断p节点是左儿子还是右儿子    
                else if (pp.right == p)
                    pp.right = l;
                else
                    pp.left = l;
                l.right = p;
                p.parent = l;
            }
            return root;
        }

4.红黑树操作图解

  • 1.插入调整过程图解
    在这里插入图片描述2.删除调整过程图解
    在这里插入图片描述3.查询过程图解
    在这里插入图片描述4.总结
    到这里红黑树的实现就基本完成了,关于红黑树的结构的调整流程,基本都是先调整结构然后调整颜色,直到最后满足红黑树的特性要求。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!