二叉树之红黑树的c#实现

在下小白一个 如有错误请指正

上代码

using System;

//数据结构

namespace DataStructure
{
    public enum ColorType
    {
        Black = 0,
        Red,
    }

    /// <summary>
    /// 红黑树节点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class RedBlackNode<T> : TreeNode<T> where T : IComparable<T>
    {
        public RedBlackNode(T key, RedBlackNode<T> parentNode, RedBlackNode<T> rightNode, RedBlackNode<T> leftNode,
            ColorType color)
            : base(key, parentNode, rightNode, leftNode)
        {
            Mcolor = color;
            ParentNode = parentNode;
            LeftChildNodes = leftNode;
            RightChildNodes = rightNode;
        }
    }

    /// <summary>
    /// 红黑树
    /// 特性
    ///(1) 每个节点或者是黑色,或者是红色。
    ///(2) 根节点是黑色。
    ///(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
    ///(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
    ///(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
    /// </summary>
    public class RedBlackTree<T> : BinaryTree<T> where T : IComparable<T>
    {

        /// <summary>
        /// 获取父节点
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private RedBlackNode<T> ParentOf(RedBlackNode<T> node)
        {
            return (RedBlackNode<T>) node?.ParentNode;
        }

        /// <summary>
        /// 获取颜色
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private ColorType GetColor(RedBlackNode<T> node)
        {
            if (node == null)
                return ColorType.Black;
            return node.Mcolor == ColorType.Black ? ColorType.Black : ColorType.Red;
        }

        /// <summary>
        /// 设置父节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        private RedBlackNode<T> SetParent(RedBlackNode<T> node, RedBlackNode<T> parent)
        {
            return node == null ? null : parent;
        }

        /// <summary>
        /// 设置颜色为红色
        /// </summary>
        /// <param name="node"></param>
        private void SetRed(RedBlackNode<T> node)
        {
            if (node != null)
                node.Mcolor = ColorType.Red;
        }

        /// <summary>
        /// 设置颜色为黑色
        /// </summary>
        /// <param name="node"></param>
        private void SetBlack(RedBlackNode<T> node)
        {
            if (node != null)
                node.Mcolor = ColorType.Black;
        }

        /// <summary>
        /// 判断是否为红色
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private bool IsRed(RedBlackNode<T> node)
        {
            if (node == null)
                return false;
            return node.Mcolor == ColorType.Red ? true : false;
        }

        /// <summary>
        /// 判断是否是黑色
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private bool IsBlack(RedBlackNode<T> node)
        {
            if (node == null)
                return true;
            return node.Mcolor == ColorType.Black ? true : false;
        }

        /// <summary>
        /// 设置节点颜色
        /// </summary>
        /// <param name="node"></param>
        /// <param name="color"></param>
        private void SetColor(RedBlackNode<T> node, ColorType color)
        {
            if (node != null)
                node.Mcolor = color;
        }

        /// <summary>
        /// 左旋
        /// </summary>意味着把节点变成一个左节点
        /// <param name="rootNode"></param>
        private void LeftRotate(RedBlackNode<T> rootNode)
        {
            RedBlackNode<T> tempNode = rootNode.RightChildNodes as RedBlackNode<T>;

            rootNode.RightChildNodes = tempNode.LeftChildNodes;

            if (tempNode.LeftChildNodes != null)
                tempNode.LeftChildNodes.ParentNode = rootNode;

            tempNode.ParentNode = rootNode.ParentNode;
            if (rootNode.ParentNode == null)
                this.MRoot = tempNode;
            else
            {
                if (rootNode.ParentNode.LeftChildNodes == rootNode)
                    rootNode.ParentNode.LeftChildNodes = tempNode;
                else
                    rootNode.ParentNode.RightChildNodes = tempNode;
            }

            tempNode.LeftChildNodes = rootNode;

            rootNode.ParentNode = tempNode;
        }

        /// <summary>
        /// 右旋
        /// </summary>意味着把旋转的节点变成右节点
        /// <param name="rootNode"></param>
        private void RightRotate(RedBlackNode<T> rootNode)
        {
            RedBlackNode<T> tempNode = rootNode.LeftChildNodes as RedBlackNode<T>;
            rootNode.LeftChildNodes = tempNode.RightChildNodes;

            if (tempNode.RightChildNodes != null)
                tempNode.RightChildNodes.ParentNode = rootNode;

            tempNode.ParentNode = rootNode.ParentNode;
            if (rootNode.ParentNode == null)
            {
                this.MRoot = tempNode;
            }
            else
            {
                if (rootNode == rootNode.ParentNode.LeftChildNodes)
                {
                    rootNode.ParentNode.LeftChildNodes = tempNode;
                }
                else
                {
                    rootNode.ParentNode.RightChildNodes = tempNode;
                }
            }
            tempNode.RightChildNodes = rootNode;

            rootNode.ParentNode = tempNode;
        }

        /// <summary>
        /// 插入节点
        /// 把插入的节点修改为红色
        /// 因为插入红色的节点更不容易违反红黑树的特性
        /// 只是有可能违反第四条,这样只要处理使它不违反第四条就行了
        /// </summary>
        /// <param name="key">要插入的节点</param>
        public override void InsetNode(T key)
        {
            //将插入的节点修改为红色
            RedBlackNode<T> node = new RedBlackNode<T>(key, null, null, null, ColorType.Black);
            //使用二叉查找树的插入
            InsetNode(this, node);
        }

        /// <summary>
        /// 插入节点
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="node1"></param>
        protected void InsetNode(RedBlackTree<T> tree, RedBlackNode<T> node1)
        {
            base.InsetNode(tree, node1);
            node1.Mcolor = ColorType.Red;
            FixUpInsetNode(node1);
        }

        /// <summary>
        /// 红黑树插入修正函数
        /// 通过插入可能破坏了红黑树的结构 重新整理结构
        /// </summary>
        /// <param name="node"></param>
        private void FixUpInsetNode(RedBlackNode<T> node)
        {
            RedBlackNode<T> parent, gParent;
            while ((parent = ParentOf(node)) != null && IsRed(parent))
            {
                gParent = ParentOf(parent);
                //父节点是左节点
                if (parent == gParent.LeftChildNodes)
                {
                    RedBlackNode<T> uncle = gParent.RightChildNodes as RedBlackNode<T>;

                    //三种插入情况
                    //1.叔叔节点?不为空 且为红色
                    if (uncle != null && IsRed(uncle))
                    {
                        // 假设当前二叉树是这样:   g(黑)          修正之后          g(n 红)
                        //                                           / \                                             / \
                        //                                   (红)p   u(红)                         (黑)p   u(黑)
                        //                                         /                                               /
                        //                                        n(黑)                                   n(黑)  

                        //设置叔叔节点和父节点为红色 祖父节点为黑色
                        SetBlack(uncle);
                        SetBlack(parent);
                        SetRed(gParent);
                        //从下往上调整
                        node = gParent;
                        continue;
                    }
                    //2.叔叔节点 为黑色 且当前节点为右节点
                    if (parent.RightChildNodes == node)
                    {
                        // 假设当前二叉树是这样:  g(黑)          修正之后          g(黑)
                        //                                           / \                                             / \
                        //                                   (红)p   u(黑)                         (黑)n   u(黑)
                        //                                          \                                              /
                        //                                           n(黑)                              p(红)   

                        RedBlackNode<T> temp;
                        //左旋 把父节点旋转为当前节点的左节点 当前节点旋转到之前父节点的位置
                        LeftRotate(parent);
                        temp = parent;
                        parent = node;
                        node = temp;
                    }

                    //3.叔叔节点是黑色 且当前节点是左节点

                    // 假设当前二叉树是这样:   g(黑)              修正之后      p(黑)
                    //                                           / \                                               \
                    //                                    (红)p   u(黑)                                 g(红)
                    //                                         /                                                   / \ 
                    //                                        n(黑)                                 (黑)n   u(黑)

                    SetBlack(parent);
                    SetRed(gParent);
                    RightRotate(gParent);
                }
                else //父节点是右节点
                {
                    RedBlackNode<T> uncle = gParent.LeftChildNodes as RedBlackNode<T>;

                    //叔叔节点是红
                    if (uncle != null && IsRed(uncle))
                    {
                        // 假设当前二叉树是这样:   g(黑)          修正之后          g(n 红)
                        //                                           / \                                             / \
                        //                                   (红)u   p(红)                         (黑)u   p(黑)
                        //                                             /                                                /
                        //                                            n(黑)                                    n(黑)  

                        SetBlack(uncle);
                        SetBlack(parent);
                        SetRed(gParent);
                        node = gParent;
                        continue;
                    }
                    //叔叔节点是黑 且当前节点是左节点
                    if (node == parent.LeftChildNodes)
                    {
                        // 假设当前二叉树是这样:    g(黑)          修正之后          g(黑)
                        //                                           / \                                             / \
                        //                                   (红)u   p(黑)                        (黑)u   n(黑)
                        //                                             /                                                 \
                        //                                            n(黑)                                       p(红)   

                        RedBlackNode<T> temp;
                        RightRotate(parent);
                        temp = parent;
                        parent = node;
                        node = temp;
                    }

                    //叔叔节点是黑 且当前节点是右节点

                    // 假设当前二叉树是这样:    g(黑)          修正之后              p(黑)
                    //                                           / \                                                 /
                    //                                      (黑)u   p(红)                                g(红)
                    //                                               \                                             / \ 
                    //                                                n(黑)                        (黑)u   n(黑)

                    SetRed(gParent);
                    SetBlack(parent);
                    LeftRotate(gParent);
                }
            }

            SetBlack((RedBlackNode<T>) this.MRoot);
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="removeNode">删除的节点</param>
        /// <returns></returns>
        /// 1.被删除节点的左右子节点都不为空 寻找该节点的后继(取代)节点(大于该节点的最小节点)取代该节点
        /// (1)要删除的节点是根节点
        /// (2)要删除的节点不是根节点
        /// (3)要删除的节点的后继节点是他的子节点
        /// 2.要删除的节点的左节点或者右节点为空
        private void RemoveNode(RedBlackNode<T> removeNode)
        {
            RedBlackNode<T> childNode, parentNode;
            ColorType color;
            if (removeNode.LeftChildNodes != null && removeNode.RightChildNodes != null)
            {
                RedBlackNode<T> replaceNode = removeNode;
                replaceNode = replaceNode.RightChildNodes as RedBlackNode<T>;
                //寻找后继结点 红黑二叉树是有序的 所以可以这样寻找他的后继节点
                while (replaceNode.LeftChildNodes != null)
                    replaceNode = replaceNode.LeftChildNodes as RedBlackNode<T>;

                //判断要删除的节点是否是根节点
                if (ParentOf(removeNode) != null)
                {
                    //如果要删除的节点是左节点
                    if (ParentOf(removeNode).LeftChildNodes == removeNode)
                    {
                        ParentOf(removeNode).LeftChildNodes = replaceNode;
                    }
                    else
                    {
                        ParentOf(removeNode).RightChildNodes = replaceNode;
                    }
                }
                else
                {
                    this.MRoot = replaceNode;
                }
                //取代节点不存在左节点 因为replaceNode是后继节点 且 红黑二叉树是有序的
                childNode = replaceNode.RightChildNodes as RedBlackNode<T>;
                parentNode = replaceNode.ParentNode as RedBlackNode<T>;
                color = GetColor(replaceNode);
                //如果被删除的节点是取代节点的父节点
                if (parentNode == removeNode)
                {
                    parentNode = replaceNode;
                }
                else
                {
                    if (childNode != null)
                        childNode.ParentNode = parentNode;

                    parentNode.LeftChildNodes = childNode;

                    replaceNode.RightChildNodes = removeNode.RightChildNodes;

                    SetParent((RedBlackNode<T>) removeNode.RightChildNodes, replaceNode);

                }
                replaceNode.ParentNode = removeNode.ParentNode;

                //此处处理颜色 取代节点移动到的位置节点颜色不会发生混乱
                replaceNode.Mcolor = removeNode.Mcolor;

                replaceNode.LeftChildNodes = removeNode.LeftChildNodes;
                removeNode.LeftChildNodes.ParentNode = removeNode;

                //如果replaceNode为黑色 则它移走后他的子节点和父节点拼接后可能出现两个都是红 
                //可能会违反 特性 2. 4. 5
                if (color == ColorType.Black)
                {
                    //修正
                    FixUpRemove(childNode, parentNode);
                }
                removeNode = null;
                return;
            }
            //如果要删除的右节点为空
            if (removeNode.LeftChildNodes != null)
            {
                childNode = removeNode.LeftChildNodes as RedBlackNode<T>;
            }
            else //要删除的左节点为空
            {
                childNode = removeNode.RightChildNodes as RedBlackNode<T>;
            }

            parentNode = removeNode.ParentNode as RedBlackNode<T>;

            color = removeNode.Mcolor;

            //获取要删除的节点的子节点
            if (childNode != null)
                childNode.ParentNode = parentNode;

            //判断要删除的节点是否是根节点
            if (parentNode != null)
            {
                //如果要删除的节点是左节点
                if (removeNode == parentNode.LeftChildNodes)
                {
                    //父节点的左节点为子节点
                    parentNode.LeftChildNodes = childNode;
                }
                else
                {
                    parentNode.RightChildNodes = childNode;
                }
            }
            else
                this.MRoot = childNode;

            //如果要删除的为黑色
            //如果replaceNode为黑色 则它移走后他的子节点和父节点拼接后可能出现两个都是红 
            //可能会违反 特性 2. 4. 5
            if (color == ColorType.Black)
            {
                FixUpRemove(childNode, parentNode);
            }

            removeNode = null;
        }

        /// <summary>
        /// 删除修正方法
        /// 从红黑树删除节点后 红黑树失去平衡 使用此方法修正
        /// </summary>
        /// <param name="childNode"></param>
        /// <param name="parent"></param>

 

        private void FixUpRemove(RedBlackNode<T> childNode, RedBlackNode<T> parent)
        {
            RedBlackNode<T> brotherNode;
            while ((childNode == null || IsBlack(childNode)) && childNode != this.MRoot)
            {
                if (childNode == parent.LeftChildNodes)
                {
                    brotherNode = parent.RightChildNodes as RedBlackNode<T>;
                    //四种删除
                    //1.childNode的兄弟节点是红色  通过染黑兄弟节点和旋转 转化为兄弟节点为黑色的问题
                    if (IsRed(brotherNode))
                    {
                        SetBlack(brotherNode);
                        SetRed(parent);
                        LeftRotate(parent);
                        brotherNode = parent.RightChildNodes as RedBlackNode<T>;
                    }
                    //2.兄弟节点为黑色且兄弟节点的子节点也为黑色 此时通过自己节点到父节点 和通过兄弟节点到父节点经过的黑色节点数量不同 违反了特性五
                    if ((brotherNode.LeftChildNodes == null || IsBlack((RedBlackNode<T>) brotherNode.LeftChildNodes)) &&
                        (brotherNode.RightChildNodes == null || IsBlack((RedBlackNode<T>) brotherNode.RightChildNodes)))
                    {
                        SetRed(brotherNode);
                        childNode = parent;
                        parent = ParentOf(parent);
                    }
                    else
                    {
                        //3.兄弟节点是黑色 兄弟的左子节点是红色右子节点是黑色 转化为第四种情况 且不破坏 特性五
                        if (brotherNode.RightChildNodes == null ||
                            IsBlack((RedBlackNode<T>) brotherNode.RightChildNodes))
                        {
                            SetBlack((RedBlackNode<T>) brotherNode.LeftChildNodes);
                            SetRed(brotherNode);
                            RightRotate(brotherNode);
                            brotherNode = parent.RightChildNodes as RedBlackNode<T>;
                        }

                        //4.兄弟节点是黑色 兄弟节点的右子节点是红色 左子节点是任意颜色
                        //把兄弟节点染成父节点的颜色
                        SetColor(brotherNode, GetColor(parent));
                        //把父节点染成黑色
                        SetBlack(parent);
                        //把兄弟节点的右节点染成黑色
                        SetBlack((RedBlackNode<T>) brotherNode.RightChildNodes);
                        //对当前父节点进行左旋
                        LeftRotate(parent);

                        childNode = this.MRoot as RedBlackNode<T>;

                        break;
                    }
                }
                else
                {
                    brotherNode = parent.LeftChildNodes as RedBlackNode<T>;
                    if (IsRed(brotherNode))
                    {
                        SetRed(parent);
                        SetBlack(brotherNode);
                        RightRotate(parent);
                        brotherNode = parent.LeftChildNodes as RedBlackNode<T>;
                    }
                    if ((brotherNode.LeftChildNodes == null || IsBlack((RedBlackNode<T>) brotherNode.LeftChildNodes)) &&
                        (brotherNode.RightChildNodes == null || IsBlack((RedBlackNode<T>) brotherNode.RightChildNodes)))
                    {
                        SetRed(brotherNode);
                        childNode = parent;
                        parent = parent.ParentNode as RedBlackNode<T>;
                    }
                    else
                    {
                        if (brotherNode.LeftChildNodes == null || IsBlack((RedBlackNode<T>) brotherNode.LeftChildNodes))
                        {
                            SetRed(brotherNode);
                            SetBlack((RedBlackNode<T>) brotherNode.RightChildNodes);
                            LeftRotate(brotherNode);
                            brotherNode = parent.LeftChildNodes as RedBlackNode<T>;
                        }

                        SetColor(brotherNode, GetColor(parent));
                        SetBlack(parent);
                        SetBlack((RedBlackNode<T>) brotherNode.LeftChildNodes);
                        RightRotate(parent);

                        childNode = this.MRoot as RedBlackNode<T>;

                        break;
                    }
                }
            }
            if (childNode != null)
                SetBlack(childNode);
        }

        public override void RemoveNode(T key)
        {
            RemoveNode(FindNode(key, (RedBlackNode<T>) MRoot));
        }

        public RedBlackNode<T> FindNode(T key, RedBlackNode<T> treeNode)
        {
            if (treeNode == null)
            {
                return null;
            }

            int comparable = key.CompareTo(treeNode.MKey);
            if (comparable < 0)
            {
                return FindNode(key, (RedBlackNode<T>) treeNode.LeftChildNodes);
            }
            else if (comparable > 0)
            {
                return FindNode(key, (RedBlackNode<T>) treeNode.RightChildNodes);
            }
            else
            {
                return treeNode;
            }
        }

        private void print(TreeNode<T> tree, T key, int direction)
        {

            if (tree != null)
            {

                if (direction == 0) // tree是根节点
                    Console.WriteLine("{0} is root This color is:{1}", tree.MKey, tree.Mcolor);
                else // tree是分支节点
                    Console.WriteLine("{0} is {1}'s This color is:{2}", tree.MKey, key, tree.Mcolor);

                print(tree.LeftChildNodes, tree.MKey, -1);
                print(tree.RightChildNodes, tree.MKey, 1);
            }
        }

        public void print()
        {
            if (MRoot != null)
                print(MRoot, MRoot.MKey, 0);
        }
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一梭键盘任平生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值