红黑树算法实现与测试

前言

红黑树是一种特殊的二叉树,他的优点是插入、删除和查找时间复杂度都是log(n),并且只需要中序遍历就能从小到大遍历节点,常用于解决哈希冲突。
算法思路

实现代码(C#)

using System;
using System.Collections.Generic;

namespace SF_红黑树
{
    //颜色枚举
    public enum Color
    {
        RED, //红色
        BLACK//黑色
    }
    //节点
    public class TreeNode
    {
        public int address;//地址值
        public Color color;//颜色
        public bool isNull = false;//哨兵用
        private TreeNode left;//左子节点
        private TreeNode right;//右子节点
        private TreeNode parent;//父节点
        public TreeNode Left
        {
            get => left; set
            {
                left = value;
                if (value != null) value.parent = this;
            }
        }
        public TreeNode Right
        {
            get => right; set
            {
                right = value;
                if (value != null) value.parent = this;
            }
        }
        public TreeNode Parent
        {
            get => parent; set
            {
                parent = value;
            }
        }

        public TreeNode(int address = 0, TreeNode left = null, TreeNode right = null, TreeNode parent = null)
        {
            this.address = address;
            this.Left = left;
            this.Right = right;
            this.Parent = parent;
        }
        //哨兵
        public TreeNode(bool isNull)
        {
            this.isNull = isNull;
            this.color = Color.BLACK;
        }

        public static bool operator <(TreeNode x, TreeNode y)
        {
            return x.address.CompareTo(y.address) < 0;
        }

        public static bool operator >(TreeNode x, TreeNode y)
        {
            return x.address.CompareTo(y.address) > 0;
        }
    }

    public class RBTree
    {
        //保存根节点
        public TreeNode root = null;
        //左旋
        void LeftRotate(TreeNode x)
        {
            TreeNode p = x.Parent;
            TreeNode y = x.Right;
            x.Right = y.Left;
            if (p == null)
            {
                y.Parent = null;
                root = y;
            }
            else
            {
                if (p.Right == x) { p.Right = y; }
                else { p.Left = y; }
            }
            y.Left = x;
        }
        //右旋
        void RightRotate(TreeNode y)
        {
            TreeNode p = y.Parent;
            TreeNode x = y.Left;
            y.Left = x.Right;
            if (p == null)
            {
                x.Parent = null;
                root = x;
            }
            else
            {
                if (p.Right == y) { p.Right = x; }
                else { p.Left = x; }
            }
            x.Right = y;
        }
        //插入节点
        public void Insert(TreeNode z)
        {
            TreeNode x = root;
            TreeNode y = null;
            while (x != null)
            {
                y = x;
                if (z < x) { x = x.Left; }
                else { x = x.Right; }
            }
            if (y == null) { root = z; }
            else if (z < y) { y.Left = z; }
            else { y.Right = z; }
            z.Left = null;
            z.Right = null;
            z.color = Color.RED;
            FixUp_Insert(z);
        }
        //插入节点后矫正红黑树
        void FixUp_Insert(TreeNode z)
        {
            while (z.Parent != null && z.Parent.color == Color.RED)
            {
                TreeNode p = z.Parent;
                TreeNode pp = z.Parent.Parent;
                TreeNode y;
                if (p == pp.Left)//父节点是左节点(叔叔为右)
                {
                    y = pp.Right;
                    if (y != null && y.color == Color.RED)//case1:叔叔节点颜色是红色
                    {
                        p.color = Color.BLACK;
                        y.color = Color.BLACK;
                        pp.color = Color.RED;
                        z = pp;
                    }
                    else if (z == p.Right)//case2:叔叔节点是黑色,且当前节点是右节点
                    {
                        z = p;
                        LeftRotate(z);
                    }
                    else if (z == p.Left)//case2:叔叔节点是黑色,且当前节点是左节点
                    {
                        p.color = Color.BLACK;
                        pp.color = Color.RED;
                        RightRotate(pp);
                    }
                }
                else//父节点是右节点(叔叔为左)
                {
                    y = pp.Left;
                    if (y != null && y.color == Color.RED)
                    {
                        p.color = Color.BLACK;
                        y.color = Color.BLACK;
                        pp.color = Color.RED;
                        z = pp;
                    }
                    else if (z == p.Left)
                    {
                        z = p;
                        RightRotate(z);
                    }
                    else if (z == p.Right)
                    {
                        p.color = Color.BLACK;
                        pp.color = Color.RED;
                        LeftRotate(pp);
                    }
                }

            }
            root.color = Color.BLACK;//根节点颜色置为黑
        }
        //删除节点
        public void Delete(int address)
        {
            TreeNode z = FindNode(address);
            if (z == null) return;
            TreeNode y;
            if (z.Left == null || z.Right == null) { y = z; }//当前节点的子节点为非双空
            else { y = FindSuccessorNode(z); }//当前节点的子节点为双空,找后继节点
            TreeNode x = null;

            if (y.Left != null) { x = y.Left; }
            else { x = y.Right; }

            //x作为哨兵不能为空
            if (x == null && y.color == Color.BLACK) { x = new TreeNode(true); }

            //用y的子节点代替y
            if (y.Parent == null) { root = x; }
            else if (y.Parent.Left == y) { y.Parent.Left = x; }
            else { y.Parent.Right = x; }

            if (y != z) { z.address = y.address; }//将y的值赋值给z
            if (y.color == Color.BLACK) { FixedUp_Delete(x); }//如果删除的y为黑节点,那么矫正红黑树
        }
        //查找结点
        public TreeNode FindNode(int address)
        {
            TreeNode y = root;
            while (y != null)
            {
                if (address > y.address) { y = y.Right; }
                else if (address < y.address) { y = y.Left; }
                else { return y; }
            }
            return null;
        }
        //删除节点后矫正红黑树
        void FixedUp_Delete(TreeNode x)
        {
            TreeNode org = x;//记录哨兵
            //Console.WriteLine(x.isNull);
            while (true)
            {
                if (x == root || x.color == Color.RED)//如果当前节点是根节点或为红节点
                {
                    x.color = Color.BLACK;
                    break;
                }
                TreeNode w;
                if (x == x.Parent.Left)//当前节点为左节点
                {
                    w = x.Parent.Right;
                    if (w != null)//如果当前节点的兄弟节点不为null
                    {
                        if (w.color == Color.RED)//case1:当前节点为黑+黑 兄弟节点为红
                        {
                            x.Parent.color = Color.RED;
                            w.color = Color.BLACK;
                            LeftRotate(x.Parent);
                        }
                        else if ((w.Left == null || w.Left.color == Color.BLACK) && (w.Right == null || w.Right.color == Color.BLACK))//case2:当前节点为黑+黑,兄弟节点和其子节点都为黑
                        {
                            w.color = Color.RED;
                            x = x.Parent;
                        }
                        else if ((w.Left != null && w.Left.color == Color.RED) && (w.Right == null || w.Right.color == Color.BLACK))//case3:当前节点为黑+黑,兄弟节点为黑,左孩子为红,右孩子为黑
                        {
                            w.color = Color.RED;
                            w.Left.color = Color.BLACK;
                            RightRotate(w);
                            w = x.Parent.Right;
                        }
                        else if (w.Right != null && w.Right.color == Color.RED)//case4:当前节点为黑+黑,兄弟节点为黑,右孩子为红
                        {
                            w.color = x.Parent.color;
                            x.Parent.color = Color.BLACK;
                            w.Right.color = Color.BLACK;
                            LeftRotate(x.Parent);
                            x = root;
                        }
                    }
                    else
                    {
                        x = x.Parent;//反之将当前节点设为父节点
                    }
                }
                else//当前节点为右节点(操作和上面相反)
                {
                    w = x.Parent.Left;
                    if (w != null)
                    {
                        if (w.color == Color.RED)
                        {
                            x.Parent.color = Color.RED;
                            w.color = Color.BLACK;
                            RightRotate(x.Parent);
                        }
                        else if ((w.Left == null || w.Left.color == Color.BLACK) && (w.Right == null || w.Right.color == Color.BLACK))
                        {
                            w.color = Color.RED;
                            x = x.Parent;
                        }
                        else if ((w.Right != null && w.Right.color == Color.RED) && (w.Left == null || w.Left.color == Color.BLACK))
                        {
                            w.color = Color.RED;
                            w.Right.color = Color.BLACK;
                            LeftRotate(w);
                            w = x.Parent.Left;
                        }
                        else if (w.Left != null && w.Left.color == Color.RED)
                        {
                            w.color = x.Parent.color;
                            x.Parent.color = Color.BLACK;
                            w.Left.color = Color.BLACK;
                            RightRotate(x.Parent);
                            x = root;
                        }
                    }
                    else
                    {
                        x = x.Parent;
                    }
                }
            }
            //如果哨兵为空,则删除哨兵
            if (org.isNull)
            {
                if (org.Parent == null) { root = null; }
                else if (org.Parent.Left == org) { org.Parent.Left = null;  }
                else { org.Parent.Right = null; }
                org = null;
            }
        }
        //寻找后继节点
        TreeNode FindSuccessorNode(TreeNode z)
        {
            TreeNode y = z.Left;
            TreeNode ret = null;
            while (y != null)
            {
                ret = y;
                y = y.Right;
            }
            return ret;
        }
        //中序遍历->左 根 右
        public void InOrder(TreeNode node, List<int> ret)
        {
            if (node == null) return;
            InOrder(node.Left, ret);
            ret.Add(node.address);
            InOrder(node.Right, ret);
        }
        //输出节点地址信息
        public override string ToString()
        {
            List<int> ret = new List<int>();
            InOrder(root, ret);
            return string.Join(",", ret);
        }
    }
}

测试代码

class Program
{
    static void Main(string[] args)
    {
        RBTree rBTree = new RBTree();
        Random random = new Random();
        List<int> adressArry = new List<int>();
        List<int> temp = new List<int>();
        for (int i = 0; i < 1000; i++)
        {
            adressArry.Add(i);
        }
        //模拟随机分配不同地址
        for (int i = 0; i < 20; i++)
        {
            int index = random.Next(0, adressArry.Count);
            TreeNode node = new TreeNode(adressArry[index]);
            temp.Add(adressArry[index]);
            adressArry.RemoveAt(index);
            rBTree.Insert(node);
        }
        //测试删除
        for(int i = 0; i < 10; i++)
        {
            rBTree.Delete(temp[i]);
        }
        Console.WriteLine(rBTree.ToString());
    }
}

输出

在这里插入图片描述

参考文献

1, 《算法导论》(p163-p181)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值