热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据结构和算法学习笔记十六:红黑树

一.简介:红黑树是2-3-4树(一种B树)的实现,所以如果想要理解红黑树的增删操作的原理,必须先了解2-3-4树的增删操作步骤.将红黑树转化为对应的2-3-4树,只需要理解黑色节点

一.简介:

  红黑树是2-3-4树(一种B树)的实现,所以如果想要理解红黑树的增删操作的原理,必须先了解2-3-4树的增删操作步骤.将红黑树转化为对应的2-3-4树,只需要理解黑色节点才是真正的节点,红色节点是从属于黑色节点的,如下图的红黑树和对应的2-3-4树:

  参考资料:一般的做法是将参考资料放在最后的,但是我习惯于将参考资料放在简介中.

    1)挑战全B站的红黑树视频,不服来战!终结B站没人能讲清楚红黑树的历史!_哔哩哔哩_bilibili.讲解java中treemap数据结构(底层是红黑树)的实现原理,在讲解的过程中对照2-3-4树详细梳理了红黑树的规则的由来和增删实现,讲解的很细致但是有一定基础的同志会觉得他很啰嗦,适合完全没有基础的人观看.个人觉得后半部分红黑树的删除讲得有些乱.

    2)红黑树第一讲_哔哩哔哩_bilibili;  红黑树第二讲_哔哩哔哩_bilibili.  使用C++手撕红黑树,在评论区作者将视频和其中用到的文档课件\源码等放到了度盘中并提供了下载地址,这里也一并粘贴:

      地址:https://pan.baidu.com/s/1dCUtkYHRjxzdGGogKv8vaQ
      密码:pg9c

    这个作者将红黑树的增删过程中遇到的情况分类得很详细,并且将增加节点时双红的解决方案和删除节点时失黑的解决方案梳理得很具体,强烈推荐.本文中部分图片(如上面的2-3-4树和红黑树对应图)也来自于这个作者的文档课件.

二.红黑树的性质

  1.红黑树的性质说明:红黑树既然是2-3-4树的实现,那么红黑树的性质就一定是为了使这棵树对应的2-3-4树合乎2-3-4树的规则.因此,要理解红黑树的性质,有必要先理解2-3-4树.2-3-4树是B树的一种,关于B树需要满足的条件及其增删操作的步骤可以参考:数据结构和算法学习笔记十五:多路查找树(B树) - movin2333 - 博客园 (cnblogs.com).在这篇博客中以最简单的2-3树为例讲解了B树的性质和增删操作,2-3-4树的相应增删操作类推即可,如有必要读者也可自行查找资料了解2-3-4树.

  2.红黑树的性质:

    1)红黑树是一颗平衡二叉树,其中序遍历结果单调不减.

    2)节点是红色或者黑色.

    3)根节点是黑色.

    4)每个叶节点是黑色的.这里的叶节点是指如果某个节点的左右子节点指针中有空值时用来替换这个空值的Null节点.

    5)每个红色节点的两个子节点都是黑色节点.换言之,不存在父子节点颜色都是红色的情况.

    6)从根节点到每个叶子节点的每一条路径中黑色节点的数量都是相同的.黑色节点的数量叫黑高度.

  3.红黑树的性质和2-3-4树的一些关联:

    如上图所示,首先2-3-4树本身就是一颗平衡的二叉树,其中序遍历的结果单调不减,因此对应的红黑树也具有相同的性质.其次,在红黑树对应的2-3-4树中,我们发现2-3-4树中的每一种节点都和红黑树中的节点之间有对应关系,这里不详细列举.性质5说不存在两个连续红色节点,也是因为红黑树中两个连续的红色节点的情况在2-3-4树中找不到节点或节点之间的关联情况与之映射.性质6中的黑高度应该很好理解,在2-3-4树中所有叶子节点都在同一层,2-3-4树中每个节点对应到红黑树中都是1个黑色节点和0-2个红色节点.

三.向红黑树中增加元素:

  如果向红黑树中增加元素,首先将红黑树当做一颗普通二叉树,使用循环遍历的方法找到要增加节点的位置,然后添加节点.添加的节点默认都是红色的,在添加完成节点后,需要注意有可能遇到连续红色节点的情况,需要进行双红修正.对应到2-3-4树中,添加节点时如果添加到2节点可以直接添加,2节点变为3节点;添加到3节点上,也是直接添加,3节点变为4节点,但是4节点的黑色元素一定是3个元素中中间的那个,所以可能需要修正节点颜色;添加到4节点上时无法直接添加,需要先将原4节点的3个元素中中间的那个挤到父节点中再将剩下两个元素拆成两个2节点,之后再添加节点,而一个元素被挤到父节点中时父节点也可能需要修正.不论2-3-4树中的情况如何,在红黑树中,添加节点时只要遇到了双红现象就需要修正.双红现象又分为以下几种:

  1.添加节点时父节点为黑色,没有双红现象发生;

  2.叔叔节点是黑色节点或Null节点,这种情况对应到2-3-4树中就是插入到3节点中,只需要进行1-2次旋转和相应的变色即可;

  3.叔叔节点是红色,这种情况对应到2-3-4树中就是插入到4节点中,原来的4节点会分裂为两个2节点再添加元素,这时需要递归.

四.移除红黑树中的元素:

  红黑树的删除操作相对是比增加操作麻烦的,我们同样先简单梳理2-3-4树中的元素删除:

  在2-3-4树中,如果被移除的元素是叶子节点上的元素,且这个叶子节点是3节点或4节点,那么直接移除就好,但是如果这个叶子节点是2节点,则需要找这个节点的后继节点或前驱节点代替这个节点,然后删除前驱节点或后继节点.如果被移除的元素不在叶子节点中,那么同样找到它的前驱节点或后继节点替换它,移除前驱或后继,移除时可以继续找其前驱或后继替换,知道被移除的节点在叶子节点中.

  在红黑树中,同样首先找到要移除元素的位置,找到后如果这个节点是一个叶子节点(这里叶子节点不是指Null节点,而是指当前节点的左右子节点指针都为空),直接删除,如果是黑色的节点或不是叶子节点,则找这个节点的前驱节点或后继节点进行替换,替换后继续判断这个节点是否是叶子节点,是就可以删除了.如果叶子节点是红色,直接删除(对应移除2-3-4树中的3节点或4节点),但是叶子节点是黑色的话,就不能直接删除(对应移除2-3-4树中的2节点),删除后会破坏整棵树的平衡,这种情况下需要对移除节点后的红黑树进行重新平衡,这个平衡过程就叫失黑修正.失黑修正的步骤可以分以下几种情况:

  1.没有红色侄子,父节点为红色.这种情况的失黑修正只需将父节点变为黑色,兄弟节点变为红色即可.对应2-3-4树中的情况就是在移除2节点时父节点为3节点或4节点,兄弟节点也是2节点,将父节点变为2节点或3节点,多出来的元素移动到兄弟节点中去,这样这个2节点就可以直接移除.

  2.有红色侄子,父节点为红色.这种情况的失黑修正只需要在移除后进行一次或两次旋转操作,然后进行染色,染色的结果是父节点位置的新节点为红色,其子节点都为黑色.对应到2-3-4树中,这个操作就是移除2节点时,兄弟节点是3节点或4节点,可以借用父节点中的元素来填补2节点移除后的空缺位置,再从兄弟节点中借用1-2个元素填补父节点被移除后的空缺位置.

  3.没有红色侄子,父节点为黑色,兄弟节点为黑色.这种情况的失黑修正无法从兄弟节点找元素补齐,因此会降低红黑树的层数.具体做法是将兄弟节点变为红色,然后向上递归进行失黑修正.

  4.父节点为黑色,兄弟节点为红色.这种情况下因为红黑树的不同分支黑高度相同,因此红色的兄弟节点一定有两个黑色的子节点,这时进行一次旋转,就可以将这种情况转化为其他情况.

五.红黑树的增删实现代码(C#):

/************************************
* 创建人:movin
* 创建时间:2021/7/28 21:09:48
* 版权所有:个人
***********************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace SearchCore
{
    /// 
    /// 红黑树节点类
    /// 
    public class RedBlackNode
    {
        /// 
        /// 保存的数据
        /// 
        public int Content { get; set; }
        /// 
        /// 左子节点
        /// 
        public RedBlackNode LeftChild { get; private set; }
        /// 
        /// 右子节点
        /// 
        public RedBlackNode RightChild { get; private set; }
        /// 
        /// 颜色
        /// 
        public Color Color { get; private set; }
        /// 
        /// 父节点
        /// 
        public RedBlackNode Parent { get; private set; }
        public RedBlackNode(int content,RedBlackNode parent)
        {
            Content = content;
            Parent = parent;
            //初始节点都是红色
            Color = Color.RED;
        }
        /// 
        /// 添加左子节点
        /// 
        /// 
        public void AddLeftChild(RedBlackNode leftChild)
        {
            LeftChild = leftChild;
            if(leftChild != null)
            {
                leftChild.Parent = this;
            }
        }
        /// 
        /// 添加右子节点
        /// 
        /// 
        public void AddRightChild(RedBlackNode rightChild)
        {
            RightChild = rightChild;
            if(rightChild != null)
            {
                rightChild.Parent = this;
            }
        }
        /// 
        /// 设置颜色
        /// 
        /// 
        public void SetColor(Color color)
        {
            Color = color;
        }
    }
    /// 
    /// 红黑树的节点颜色
    /// 
    public enum Color
    {
        RED,
        BLACK,
    }
}
/************************************
* 创建人:movin
* 创建时间:2021/7/28 21:10:19
* 版权所有:个人
***********************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace SearchCore
{
    public class RedBlackTree
    {
        /// 
        /// 根节点
        /// 
        public RedBlackNode Root { get; private set; }
        /// 
        /// 节点数量
        /// 
        public int Count { get; private set; }

        public RedBlackTree()
        {
            Count = 0;
        }
        #region add and remove node
        public void Remove(int content)
        {
            if(Root == null)
            {
                return;
            }
            RedBlackNode removeNode = RealRemove(content, Root);
            if(removeNode != null)
            {
                //实际的节点移除操作
                if (removeNode.Parent == null)
                {
                    Root = null;
                }
                else
                {
                    if (removeNode.Parent.LeftChild == removeNode)
                    {
                        removeNode.Parent.AddLeftChild(null);
                    }
                    else
                    {
                        removeNode.Parent.AddRightChild(null);
                    }
                }
                //节点数量减少
                Count--;
            }
        }
        /// 
        /// 真正移除节点的方法,递归
        /// 
        /// 
        /// 
        private RedBlackNode RealRemove(int content,RedBlackNode node)
        {
            if(content < node.Content)
            {
                if(node.LeftChild != null)
                {
                    return RealRemove(content, node.LeftChild);
                }
            }
            else if(content > node.Content)
            {
                if(node.RightChild != null)
                {
                    return RealRemove(content, node.RightChild);
                }
            }
            //要删除的值和当前节点的值相等时,当前节点就是要删除的节点
            else
            {
                //找到真正要删除的节点(找当前节点的前驱节点或后继节点,并在找到后就交换数据,并递归或循环继续找,直到找到某个叶子节点身上)
                var realDeleteNode = GetRealDeleteNode(node);
                //找到的叶子节点是黑色节点,需要进行失黑修正,再移除;是红色节点,不用失黑修正,直接移除
                if(realDeleteNode.Color == Color.BLACK)
                {
                    LoseBlackAdjust(realDeleteNode);
                }
                //返回被移除的节点
                return realDeleteNode;
            }
            return null;
        }
        /// 
        /// 添加节点
        /// 
        /// 
        public void Add(int content)
        {
            RedBlackNode newNode = null;
            if (Root == null)
            {
                newNode = new RedBlackNode(content, null);
                Root = newNode;
            }
            else
            {
                newNode = RealAddNode(content, Root);
            }
            //如果成功插入了节点,需要作双红修正
            if(newNode != null)
            {
                RedRedAdjust(newNode);
                Count++;
            }
            
        }
        /// 
        /// 真正添加节点的方法,会递归
        /// 
        /// 
        /// 
        private RedBlackNode RealAddNode(int content, RedBlackNode node)
        {
            if (content < node.Content)
            {
                if (node.LeftChild == null)
                {
                    node.AddLeftChild(new RedBlackNode(content, node));
                    return node.LeftChild;
                }
                return RealAddNode(content, node.LeftChild);
            }
            else if (content > node.Content)
            {
                if (node.RightChild == null)
                {
                    node.AddRightChild(new RedBlackNode(content, node));
                    return node.RightChild;
                }
                return RealAddNode(content, node.RightChild);
            }
            else
            {
                return null;
            }
        }
        #endregion
        #region lose black adjust
        #region lose black adjust
        /// 
        /// 失黑修正
        /// 
        /// 
        private void LoseBlackAdjust(RedBlackNode deleteNode)
        {
            if(deleteNode.Parent != null)
            {
                if(deleteNode.Parent.RightChild == deleteNode)
                {
                    LoseBlackAdjustRight(deleteNode.Parent);
                }
                else
                {
                    LoseBlackAdjustLeft(deleteNode.Parent);
                }
            }
            else
            {
                //没有父节点的节点是根节点,根节点必须是黑色节点
                deleteNode.SetColor(Color.BLACK);
            }
        }
        /// 
        /// 失黑修正-移除左子黑色节点
        /// 
        /// 
        private void LoseBlackAdjustLeft(RedBlackNode root)
        {
            if(root.Color == Color.BLACK)
            {
                if(root.RightChild.Color == Color.RED)
                {
                    LoseBlackAdjust_BlackParent_RedBrother_Left(root);
                }
                else
                {
                    //兄弟节点为黑色,如果有侄子,侄子节点一定是红色
                    if(root.RightChild.LeftChild != null || root.RightChild.RightChild != null)
                    {
                        LoseBlackAdjust_WithRedNephew_Left(root);
                    }
                    else
                    {
                        LoseBlackAdjust_BlackParent_BlackBrother_WithoutRedNephew_Left(root);
                    }
                }
            }
            else
            {
                if(root.RightChild.LeftChild != null || root.RightChild.RightChild != null)
                {
                    LoseBlackAdjust_WithRedNephew_Left(root);
                }
                else
                {
                    LoseBlackAdjust_RedParent_BlackBrother_WithoutRedNephew_Left(root);
                }
            }
        }
        /// 
        /// 失黑修正-移除右子黑色节点
        /// 
        /// 
        private void LoseBlackAdjustRight(RedBlackNode root)
        {
            if (root.Color == Color.BLACK)
            {
                if (root.LeftChild.Color == Color.RED)
                {
                    LoseBlackAdjust_BlackParent_RedBrother_Right(root);
                }
                else
                {
                    //兄弟节点为黑色,如果有侄子,侄子节点一定是红色
                    if (root.LeftChild.LeftChild != null || root.LeftChild.RightChild != null)
                    {
                        LoseBlackAdjust_WithRedNephew_Right(root);
                    }
                    else
                    {
                        LoseBlackAdjust_BlackParent_BlackBrother_WithoutRedNephew_Right(root);
                    }
                }
            }
            else
            {
                if (root.LeftChild.LeftChild != null || root.LeftChild.RightChild != null)
                {
                    LoseBlackAdjust_WithRedNephew_Right(root);
                }
                else
                {
                    LoseBlackAdjust_RedParent_BlackBrother_WithoutRedNephew_Right(root);
                }
            }
        }
        #endregion
        #region with red nephew
        /// 
        /// 失黑修正-有红色侄子-移除的黑色节点在根节点左边
        /// 
        /// 
        private void LoseBlackAdjust_WithRedNephew_Left(RedBlackNode root)
        {
            //如果没有右子节点的右子节点,要先触发一次右旋
            if(root.RightChild.RightChild == null)
            {
                RightRotate(root.RightChild);
                root.RightChild.SetColor(Color.BLACK);
                root.RightChild.RightChild.SetColor(Color.RED);
            }
            //触发一次左旋
            LeftRotate(root);
            //旋转后变色(注意:旋转后root已经不在根节点的位置上了)
            Color parentColor = root.Color;//保存原来的根节点颜色
            root.SetColor(Color.BLACK);
            root.Parent.SetColor(parentColor);//根节点颜色不变
            root.Parent.RightChild.SetColor(Color.BLACK);
        }
        /// 
        /// 失黑修正-有红色侄子-移除的黑色节点在根节点右边
        /// 
        /// 
        private void LoseBlackAdjust_WithRedNephew_Right(RedBlackNode root)
        {
            //如果没有左子节点的左子节点,要先触发一次右旋
            if (root.LeftChild.LeftChild == null)
            {
                LeftRotate(root.LeftChild);
                root.LeftChild.SetColor(Color.BLACK);
                root.LeftChild.LeftChild.SetColor(Color.RED);
            }
            //触发一次右旋
            RightRotate(root);
            //旋转后变色(注意:旋转后root已经不在根节点的位置上了)
            Color parentColor = root.Color;//保存原来的根节点颜色
            root.SetColor(Color.BLACK);
            root.Parent.SetColor(parentColor);//根节点颜色不变
            root.Parent.LeftChild.SetColor(Color.BLACK);
        }
        #endregion
        #region without red nephew
        /// 
        /// 失黑修正-黑色父节点-黑色兄弟节点-没有红色侄子-移除的黑色节点在根节点左边
        /// 
        /// 
        private void LoseBlackAdjust_BlackParent_BlackBrother_WithoutRedNephew_Left(RedBlackNode root)
        {
            root.RightChild.SetColor(Color.RED);
            LoseBlackAdjust(root);
        }
        /// 
        /// 失黑修正-黑色父节点-黑色兄弟节点-没有红色侄子-移除的黑色节点在根节点右边
        /// 
        /// 
        private void LoseBlackAdjust_BlackParent_BlackBrother_WithoutRedNephew_Right(RedBlackNode root)
        {
            root.LeftChild.SetColor(Color.RED);
            LoseBlackAdjust(root);
        }
        /// 
        /// 失黑修正-红色父节点-黑色兄弟节点-没有红色侄子-移除的黑色节点在根节点左边
        /// 
        /// 
        private void LoseBlackAdjust_RedParent_BlackBrother_WithoutRedNephew_Left(RedBlackNode root)
        {
            root.SetColor(Color.BLACK);
            root.RightChild.SetColor(Color.RED);
        }
        /// 
        /// 失黑修正-红色父节点-黑色兄弟节点-没有红色侄子-移除的黑色节点在根节点右边
        /// 
        /// 
        private void LoseBlackAdjust_RedParent_BlackBrother_WithoutRedNephew_Right(RedBlackNode root)
        {
            root.SetColor(Color.BLACK);
            root.LeftChild.SetColor(Color.RED);
        }
        /// 
        /// 失黑修正-黑色父节点-红色兄弟节点-移除的黑色节点在根节点左边
        /// 
        /// 
        private void LoseBlackAdjust_BlackParent_RedBrother_Left(RedBlackNode root)
        {
            if(root.RightChild.RightChild == null)
            {
                RightRotate(root.RightChild);
                root.RightChild.RightChild.SetColor(Color.BLACK);
            }
            else
            {
                root.RightChild.SetColor(Color.BLACK);
            }
            LeftRotate(root);
            root.SetColor(Color.RED);
            //旋转后还要继续修正
            LoseBlackAdjustLeft(root);
        }
        /// 
        /// 失黑修正-黑色父节点-红色兄弟节点-移除的黑色节点在根节点右边
        /// 
        /// 
        private void LoseBlackAdjust_BlackParent_RedBrother_Right(RedBlackNode root)
        {
            if (root.LeftChild.LeftChild == null)
            {
                LeftRotate(root.LeftChild);
                root.LeftChild.LeftChild.SetColor(Color.BLACK);
            }
            else
            {
                root.LeftChild.SetColor(Color.BLACK);
            }
            RightRotate(root);
            root.SetColor(Color.RED);
            //旋转后还要继续修正
            LoseBlackAdjustLeft(root);
        }
        #endregion
        #endregion
        #region red red adjust
        #region red red adjust
        /// 
        /// 双红在根节点左边时判断进行哪种修正,并进行双红修正
        /// 
        /// 
        private void RedRedAdjust_Left(RedBlackNode root)
        {
            //校验不是双红直接返回
            if (root.LeftChild.Color == Color.BLACK)
            {
                return;
            }
            //右节点为空或者右子节点颜色为黑,对应2-3-4树中的3节点
            if (root.RightChild == null || root.RightChild.Color == Color.BLACK)
            {
                if (root.LeftChild.LeftChild != null && root.LeftChild.LeftChild.Color == Color.RED)
                {
                    RedRedAdjust_UncleBlack_LeftLeft(root);
                }
                else
                {
                    RedRedAdjust_UncleBlack_LeftRight(root);
                }
            }
            //右子节点颜色为红色,对应2-3-4树中的4节点
            else
            {
                RedRedAdjust_UncleRed_Left(root);
            }
        }
        /// 
        /// 双红在根节点右边时判断进行哪种修正,并进行双红修正
        /// 
        /// 
        private void RedRedAdjust_Right(RedBlackNode root)
        {
            //校验不是双红直接返回
            if (root.RightChild.Color == Color.BLACK)
            {
                return;
            }
            //右节点为空或者右子节点颜色为黑,对应2-3-4树中的3节点
            if (root.LeftChild == null || root.LeftChild.Color == Color.BLACK)
            {
                if (root.RightChild.RightChild != null && root.RightChild.RightChild.Color == Color.RED)
                {
                    RedRedAdjust_UncleBlack_RightRight(root);
                }
                else
                {
                    RedRedAdjust_UncleBlack_RightLeft(root);
                }
            }
            //右子节点颜色为红色,对应2-3-4树中的4节点
            else
            {
                RedRedAdjust_UncleRed_Right(root);
            }
        }
        /// 
        /// 新插入节点时进行双红修正
        /// 
        /// 
        private void RedRedAdjust(RedBlackNode newNode)
        {
            //校验父节点和爷爷节点是否存在,父节点不存在,则这是第一个根节点,爷爷节点不存在则这是第2个或可能是第3个节点
            if (newNode.Parent == null)
            {
                //根节点必须为黑色
                newNode.SetColor(Color.BLACK);
                return;
            }
            if (newNode.Parent.Parent == null)
            {
                return;
            }
            if (newNode.Parent == newNode.Parent.Parent.LeftChild)
            {
                RedRedAdjust_Left(newNode.Parent.Parent);
            }
            else
            {
                RedRedAdjust_Right(newNode.Parent.Parent);
            }
        }
        #endregion
        #region black uncle
        /// 
        /// 叔叔节点为黑色时的双红修正(新插入节点在父节点左侧,在根节点左侧)
        /// 
        /// 双红调整前的根节点
        private void RedRedAdjust_UncleBlack_LeftLeft(RedBlackNode grandpa)
        {
            RightRotate(grandpa);
            //调整颜色(注意:右旋后grandpa已经不是根节点了)
            grandpa.SetColor(Color.RED);
            grandpa.Parent.SetColor(Color.BLACK);
        }
        /// 
        /// 叔叔节点为黑色时的双红修正(新插入节点在父节点右侧,在根节点左侧)
        /// 
        /// 双红调整前的根节点
        private void RedRedAdjust_UncleBlack_LeftRight(RedBlackNode grandpa)
        {
            //先左旋转化为左左的情况
            LeftRotate(grandpa.LeftChild);
            //调用左左情况的修正函数
            RedRedAdjust_UncleBlack_LeftLeft(grandpa);
        }
        /// 
        /// 叔叔节点为黑色时的双红修正(新插入节点在父节点右侧,在根节点右侧)
        /// 
        /// 双红调整前的根节点
        private void RedRedAdjust_UncleBlack_RightRight(RedBlackNode grandpa)
        {
            LeftRotate(grandpa);
            //调整颜色
            grandpa.SetColor(Color.RED);
            grandpa.Parent.SetColor(Color.BLACK);
        }
        /// 
        /// 叔叔节点为黑色时的双红修正(新插入节点在父节点左侧,在根节点右侧)
        /// 
        /// 双红调整前的根节点
        private void RedRedAdjust_UncleBlack_RightLeft(RedBlackNode grandpa)
        {
            //先右旋转化为右右的情况
            RightRotate(grandpa.RightChild);
            //调用右右的修正函数
            RedRedAdjust_UncleBlack_RightRight(grandpa);

        }
        #endregion
        #region red uncle
        /// 
        /// 叔叔节点为黑色时的双红修正(新插入节点在根节点的左子树)
        /// 
        /// 双红调整前的根节点
        private void RedRedAdjust_UncleRed_Left(RedBlackNode grandpa)
        {
            //直接变色(实际上对应到2-3-4树中是元素的上移和节点的分裂)
            grandpa.SetColor(Color.RED);
            grandpa.LeftChild.SetColor(Color.BLACK);
            //检验是否是根节点,如果是根节点需要增加树的深度,并终止递归
            if (grandpa.Parent == null)
            {
                //将根节点的颜色改为黑色,红色的叔叔节点改为黑色,树就增长了
                grandpa.SetColor(Color.BLACK);
                grandpa.RightChild.SetColor(Color.BLACK);
                //无论如何,递归到根节点后都不需要再递归
                return;
            }
            //向上两层节点不存在也就不用递归了(说明父节点是根节点,一定是黑色)
            if (grandpa.Parent.Parent == null)
            {
                grandpa.RightChild.SetColor(Color.BLACK);
                return;
            }
            //继续向上递归(向上两层)
            if (grandpa.Parent.Parent.RightChild == grandpa.Parent)
            {
                RedRedAdjust_Right(grandpa.Parent.Parent);
            }
            else
            {
                RedRedAdjust_Left(grandpa.Parent.Parent);
            }
            grandpa.RightChild.SetColor(Color.BLACK);
        }
        /// 
        /// 叔叔节点为黑色时的双红修正(新插入节点在根节点的右子树)
        /// 
        /// 双红调整前的根节点
        private void RedRedAdjust_UncleRed_Right(RedBlackNode grandpa)
        {
            //直接变色(实际上对应到2-3-4树中是元素的上移和节点的分裂)
            grandpa.SetColor(Color.RED);
            grandpa.RightChild.SetColor(Color.BLACK);
            //检验是否是根节点,如果是根节点需要增加树的深度,并终止递归
            if (grandpa.Parent == null)
            {
                //将根节点的颜色改为黑色,红色的叔叔节点改为黑色,树就增长了
                grandpa.SetColor(Color.BLACK);
                grandpa.LeftChild.SetColor(Color.BLACK);
                //无论如何,递归到根节点后都不需要再递归
                return;
            }
            //向上两层节点不存在也就不用递归了(说明父节点是根节点,一定是黑色)
            if (grandpa.Parent.Parent == null)
            {
                grandpa.LeftChild.SetColor(Color.BLACK);
                return;
            }
            //继续向上递归(向上两层)
            if (grandpa.Parent.Parent.RightChild == grandpa.Parent)
            {
                RedRedAdjust_Right(grandpa.Parent.Parent);
            }
            else
            {
                RedRedAdjust_Left(grandpa.Parent.Parent);
            }
            grandpa.LeftChild.SetColor(Color.BLACK);
        }
        #endregion
        #endregion
        #region leftRotate and rightRotate
        /// 
        /// 左旋操作,只做节点的位置变化,不作颜色变化
        /// 
        /// 左旋前的根节点
        private void LeftRotate(RedBlackNode root)
        {
            if (root.RightChild == null)
            {
                return;
            }
            var temp = root.RightChild;
            root.AddRightChild(temp.LeftChild);
            if (root.Parent != null)
            {
                if (root.Parent.RightChild == root)
                {
                    root.Parent.AddRightChild(temp);
                }
                else
                {
                    root.Parent.AddLeftChild(temp);
                }
            }
            else
            {
                Root = temp;
                temp.SetParent(null);
            }
            temp.AddLeftChild(root);
        }
        /// 
        /// 右旋操作,只做节点的位置变化,不作颜色变化
        /// 
        /// 右旋前的根节点
        private void RightRotate(RedBlackNode root)
        {
            if (root.LeftChild == null)
            {
                return;
            }
            var temp = root.LeftChild;
            root.AddLeftChild(temp.RightChild);
            if (root.Parent != null)
            {
                if (root.Parent.RightChild == root)
                {
                    root.Parent.AddRightChild(temp);
                }
                else
                {
                    root.Parent.AddLeftChild(temp);
                }
            }
            else
            {
                Root = temp;
                temp.SetParent(null);
            }
            temp.AddRightChild(root);
        }
        #endregion
        #region find real delete node
        /// 
        /// 找到真正该删除的节点
        /// 
        /// 
        /// 
        private RedBlackNode GetRealDeleteNode(RedBlackNode currentNode)
        {
            RedBlackNode result = currentNode;
            while (result.LeftChild != null || result.RightChild != null)
            {
                RedBlackNode temp;
                if(result.LeftChild != null)
                {
                    //找到左邻居
                    temp = result.RightChild;
                    while (temp.LeftChild != null)
                    {
                        temp = temp.LeftChild;
                    }
                }
                else
                {
                    //找到右邻居
                    temp = result.LeftChild;
                    while (temp.RightChild != null)
                    {
                        temp = temp.RightChild;
                    }
                }
                //交换节点
                result.COntent= result.Content ^ temp.Content;
                temp.Content = result.Content ^ temp.Content;
                result.Content = result.Content ^ temp.Content;
                //赋值
                result = temp;
            }
            //result没有子节点时(是叶子节点)返回
            return result;
        }
        #endregion
    }
}

 


推荐阅读
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文研究了使用条件对抗网络进行图片到图片翻译的方法,并提出了一种通用的解决方案。通过学习输入图像到输出图像的映射和训练相应的损失函数,我们可以解决需要不同损失函数公式的问题。实验证明该方法在合成图片、重构目标和给图片着色等多个问题上都很有效。这项工作的重要发现是不再需要人为构建映射函数和损失函数,同时能够得出合理的结果。本文的研究对于图片处理、计算机图片合成和计算机视觉等领域具有重要意义。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • 如何使用Python从工程图图像中提取底部的方法?
    本文介绍了使用Python从工程图图像中提取底部的方法。首先将输入图片转换为灰度图像,并进行高斯模糊和阈值处理。然后通过填充潜在的轮廓以及使用轮廓逼近和矩形核进行过滤,去除非矩形轮廓。最后通过查找轮廓并使用轮廓近似、宽高比和轮廓区域进行过滤,隔离所需的底部轮廓,并使用Numpy切片提取底部模板部分。 ... [详细]
author-avatar
dsvsV
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有