HashMap中的红黑树操作以及AVL树

×本篇文章已授权微信公众号 guolin_blog (郭霖) 独家发布

红黑树

HashMap在JDK 8之后,内部存储数据时使用了红黑树(Red-Black Tree)来实现。这里就通过HashMap的源码来分析一下红黑树。

红黑树有5个原则:
1,每个节点是红色或者黑色的
2,根节点必须是黑色的
3,每个叶子节点都是黑色的空节点(NIL节点),即叶子节点不存储数据
4,红色节点的两个子节点必须都是黑色的(即路径中不能存在两个连续的红色节点)
5,从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

定义了两个属性:节点的 黑深 以及 树的 黑高
根据维基百科的定义,
节点的黑深指 从根节点到该节点的任意路径中黑色节点的数量。
树的黑高指 从根节点到叶子节点的任意路径上的黑色节点数量。

红黑树通过3种操作来维持自身的平衡(插入或删除节点后) —变色,左旋,右旋。

旋转操作:
以轴心节点为轴心,转动旋转操作节点,如果轴心节点的另一个子节点存在(非插入节点),则需要先将该节点指向到旋转操作节点的 左/右 子节点上(具体左右与旋转方向相反,即左旋则指向右子节点,右旋则指向左子节点)
在这里插入图片描述

如果旋转操作是由三角形形态变为线状形态,旋转操作节点为三角形的父节点(比如下图的节点p,节点l以及空白节点组成的三角形)
在这里插入图片描述

// HashMap源码,旋转操作
// root 为根节点,p 为旋转操作节点
/**
     变量含义:
     r:旋转操作节点的右子节点,就是待插入节点的父节点(即轴心节点)
     pp:旋转操作节点的父节点
     rl:轴心节点的左子节点    
**/
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root, TreeNode<K,V> p) {
     TreeNode<K,V> r, pp, rl;
     // 如果旋转操作节点不为空 且 轴心节点不为空,进行旋转操作
     if (p != null && (r = p.right) != null) {
         // 首先判断轴心节点的左子节点是否为NULL,如果存在需要将其指向到旋转操作节点的右子节点
         // (因为旋转后旋转操作节点会成为轴心节点的左子节点)
         if ((rl = p.right = r.left) != null)
              // 如果不为空,则建立双向关系
              // 如果为空,此时旋转操作节点的右子节点指针为空(不指向任何节点)
             rl.parent = p;
         // 判断旋转操作节点的父节点是否为空 并 将轴心节点的父节点指针指向旋转操作节点的父节点
         if ((pp = r.parent = p.parent) == null)
              // 为空,则说明旋转操作节点是根节点,节点r变为根节点并将其颜色变为黑色
             (root = r).red = false;
         // 不是根节点,就用轴心节点替换旋转操作节点
         // 根据旋转操作节点在原父节点中的位置做不同操作(原来是左子节点,则轴心节点指向左子节点;反之亦然)
         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;
     if (p != null && (l = p.left) != null) {
         if ((lr = p.left = l.right) != null)
             lr.parent = p;
         if ((pp = l.parent = p.parent) == null)
             (root = l).red = false;
         else if (pp.right == p)
             pp.right = l;
         else
             pp.left = l;
         l.right 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值