• 一个C# 泛形红黑树实现


    看了一下算法导论,纸上得来终觉浅,绝知此事要躬行,所以把感兴趣的算法就写了下。

    红黑树在插入,删除,查找过程中都可以保持较高的运行效率,sharpdevelop 中自定义的代码编辑控件中的document模型就是运用了红黑树。

    RedBlackTree.cs
    using System;

    namespace Cn.Linc.Algorithms.BasicStructure
    {
        
    public enum NodeColor
        {
            Black,
            Red
        }


        
    /// <summary>
        
    /// A binary search tree is a red-black tree if it satisfies the following red-black properties:
        
    /// 1) Every node is either red or black.
        
    /// 2) The root is black.
        
    /// 3) Every leaf (NIL) is black.
        
    /// 4) If a node is red, then both its children are black.
        
    /// 5) For each node, all paths from the node to descendant leaves contain the same number of black nodes.
        
    /// 
        
    /// Red-black trees are one of many search-tree schemes that are "balanced" in order to 
        
    /// guarantee that basic dynamic-set operations take O(lg n) time in the worst case.
        
    /// 
        
    /// Notice, a null leaf node or parent node is colored black.
        
    /// 
        
    /// More details please find in chapter 13, Introduction to Algorithms, Second Edition 
        
    /// by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein   ISBN:0262032937 
        
    /// The MIT Press © 2001 (1180 pages) 
        
    /// </summary>
        
    /// <typeparam name="T">RedBlackTreeNode type</typeparam>
        
    /// <typeparam name="S">IComparable type</typeparam>
        public class RedBlackTree<T,S>
            
    where T: RedBlackTreeNode<S> 
            
    where S: IComparable
        {
            
    private RedBlackTreeNode<S> root;

            
    /// <summary>
            
    /// Insert a new node, at first initialize the new node as red to keep the black height 
            
    /// rule of red black tree. Insert the new node to proper position accordding to its value,
            
    ///  the fix the tree according to the defination of red black tree.
            
    /// </summary>
            
    /// <param name="nodeValue"></param>
            public void InsertNode(S nodeValue)
            {
                RedBlackTreeNode
    <S> newNode = new RedBlackTreeNode<S>(nodeValue);
                
    if (root == null)
                {
                    root 
    = newNode;
                }
                
    else
                {
                    RedBlackTreeNode
    <S> tempX = root;
                    RedBlackTreeNode
    <S> tempY = null;
                    
    while (tempX != null)
                    {
                        tempY 
    = tempX;
                        tempX 
    = nodeValue.CompareTo(tempX.Value) > 0 ? tempX.RightChild : tempX.LeftChild;
                    }
                    
    if (nodeValue.CompareTo(tempY.Value) >= 0)
                    {
                        tempY.RightChild 
    = newNode;
                    }
                    
    else
                    {
                        tempY.LeftChild 
    = newNode;
                    }
                }
                InsertFixup(newNode);
            }

            
    /// <summary>
            
    /// Delete node.
            
    /// If the node only have one or no child, just delete it.
            
    /// If the node has both left and right children, find its successor, delete it and copy its 
            
    /// value to the node to be deleted.
            
    /// After deleting, fix up the tree according to defination.
            
    /// </summary>
            
    /// <param name="node"></param>
            public void DeleteNode(T node)
            {
                
    if (node == null)
                    
    return;

                
    if ((node == root) && (root.RightChild == null&& (root.LeftChild == null))
                {
                    root 
    = null;
                    
    return;
                }

                RedBlackTreeNode
    <S> tempX = null, tempY = null;
                
    if (node.LeftChild == null || node.RightChild == null)
                {
                    tempY 
    = node;
                }
                
    else
                {
                    tempY 
    = GetSuccessor(node);
                }

                tempX 
    = (tempY.LeftChild != null? tempY.LeftChild : tempY.RightChild;

                
    if (tempY.ParentNode == null)
                    root 
    = tempX;
                
    else
                {
                    
    if (tempY == tempY.ParentNode.LeftChild)
                    {
                        tempY.ParentNode.LeftChild 
    = tempX;
                    }
                    
    else
                    {
                        tempY.ParentNode.RightChild 
    = tempX;
                    }
                }

                
    if (tempY != node)
                {
                    node.Value 
    = tempY.Value;
                }

                
    // if black node is deleted the black height rule must be violated, fix it.
                if (tempY.Color == NodeColor.Black)
                    DeleteFixup(tempX,tempY.ParentNode);

            }


            
    /// <summary>
            
    /// Find the node with specified value.
            
    /// </summary>
            
    /// <param name="value">specified value</param>
            
    /// <returns></returns>
            public RedBlackTreeNode<S> FindNode(S value)
            {
                RedBlackTreeNode
    <S> temp = root;
                
    if (root == null)
                {
                    
    return null;
                }
                
    do
                {
                    
    if(value.CompareTo(temp.Value)==0)
                    {
                        
    return temp;
                    }
                    
    else if (temp.LeftChild != null && value.CompareTo(temp.Value) < 0)
                    {
                        temp 
    = temp.LeftChild;
                    }
                    
    else if (temp.RightChild != null && value.CompareTo(temp.Value) > 0)
                    {
                        temp 
    = temp.RightChild;
                    }
                    
    else
                    {
                        
    return null;
                    }
                } 
    while (true);
            }


            
    /// <summary>
            
    /// Find the successer of specific node,
            
    /// if the right child is not empty, the successor is the far left node of the subtree.
            
    /// If it has a successor and its right child is null, the successor must be the nearest
            
    /// ancestor, and the left child of the successor is ancestor of the specific node.
            
    /// </summary>
            
    /// <param name="currentNode">the specific node </param>
            
    /// <returns></returns>
            private RedBlackTreeNode<S> GetSuccessor(RedBlackTreeNode<S> currentNode)
            {
                RedBlackTreeNode
    <S> temp = null;
                
    if (currentNode.RightChild != null)
                {
                    temp 
    = currentNode.RightChild;
                    
    while (temp.LeftChild != null)
                    {
                        temp 
    = temp.LeftChild;
                    }
                    
    return temp;
                }
                
    else
                {
                    
    while (temp.ParentNode != null)
                    {
                        
    if (temp == temp.ParentNode.LeftChild)
                        {
                            
    return temp.ParentNode;
                        }
                        
    else
                        {
                            temp 
    = temp.ParentNode;
                        }
                    }
                    
    return null;
                }
            }
            
    /// <summary>
            
    /// Fix up red black tree after inserting node. Three cases:
            
    /// 1) the uncle of the node is red;
            
    /// 2) the uncle of the node is black and the node is right child(left rotate to case 3);
            
    /// 3) the uncle of the node is black and the node is left child;
            
    /// </summary>
            
    /// <param name="node"></param>
            private void InsertFixup(RedBlackTreeNode<S> node)
            {
                RedBlackTreeNode
    <S> temp = null;

                
    while (node != root && node.ParentNode.Color == NodeColor.Red)
                {
                    
    if (node.ParentNode == node.ParentNode.ParentNode.LeftChild)
                    {
                        temp 
    = node.ParentNode.ParentNode.RightChild;
                        
    if (temp != null && temp.Color == NodeColor.Red)
                        {
                            node.ParentNode.Color 
    = NodeColor.Black;
                            temp.Color 
    = NodeColor.Black;
                            node.ParentNode.ParentNode.Color 
    = NodeColor.Red;
                            node 
    = node.ParentNode.ParentNode;
                        }
                        
    else
                        {
                            
    if (node == node.ParentNode.RightChild)
                            {
                                node 
    = node.ParentNode;
                                LeftRotate(node);
                            }
                            node.ParentNode.Color 
    = NodeColor.Black;
                            node.ParentNode.ParentNode.Color 
    = NodeColor.Red;

                            RightRotate(node.ParentNode.ParentNode);
                        }
                    }
                    
    else
                    {
                        temp 
    = node.ParentNode.ParentNode.LeftChild;
                        
    if (temp != null && temp.Color == NodeColor.Red)
                        {
                            node.ParentNode.Color 
    = NodeColor.Black;
                            temp.Color 
    = NodeColor.Black;
                            node.ParentNode.ParentNode.Color 
    = NodeColor.Red;
                            node 
    = node.ParentNode.ParentNode;
                        }
                        
    else
                        {
                            
    if (node == node.ParentNode.LeftChild)
                            {
                                node 
    = node.ParentNode;
                                RightRotate(node);
                            }
                            node.ParentNode.Color 
    = NodeColor.Black;
                            node.ParentNode.ParentNode.Color 
    = NodeColor.Red;

                            LeftRotate(node.ParentNode.ParentNode);

                        }
                    }
                }
                root.Color 
    = NodeColor.Black;
            }

            
    /// <summary>
            
    /// Fix up tree property after delete node from tree
            
    /// 1) node's sibling w is red;
            
    /// 2) node's sibling w is black, and both of w's children are black;
            
    /// 3) node's sibling w is black, w's left child is red, and w's right child is black;
            
    /// 4) node's sibling w is black, and w's right child is red
            
    /// </summary>
            
    /// <param name="node"></param>
            private void DeleteFixup(RedBlackTreeNode<S> node,RedBlackTreeNode<S> parentNode)
            {
                RedBlackTreeNode
    <S> tempX = null;
                
    while (node != root && (node == null||node.Color == NodeColor.Black))
                {
                    
    if (node == parentNode.LeftChild)
                    {
                        tempX 
    = parentNode.RightChild;
                        
    if (tempX != null && tempX.Color == NodeColor.Red)
                        {
                            tempX.Color 
    = NodeColor.Black;
                            node.ParentNode.Color 
    = NodeColor.Red;
                            LeftRotate(node.ParentNode);

                        }
                        
    else
                        {
                            
    if ((tempX.LeftChild == null && tempX.RightChild == null)
                                
    || (tempX.LeftChild.Color == NodeColor.Black && tempX.RightChild.Color == NodeColor.Black))
                            {
                                tempX.Color 
    = NodeColor.Red;
                                node 
    = parentNode;
                                parentNode 
    = node.ParentNode;
                            }
                            
    else
                            {
                                
    if (tempX.RightChild == null || tempX.RightChild.Color == NodeColor.Black)
                                {
                                    
    if (tempX.RightChild != null)
                                    {
                                        tempX.LeftChild.Color 
    = NodeColor.Black;
                                        tempX.Color 
    = NodeColor.Red;
                                    }
                                    RightRotate(tempX);
                                    tempX 
    = parentNode.RightChild;
                                }
                                tempX.Color 
    = parentNode.Color;
                                parentNode.Color 
    = NodeColor.Black;
                                tempX.RightChild.Color 
    = NodeColor.Black;
                                LeftRotate(parentNode); 
                                node 
    = root;
                            }
                        }
                    }
                    
    else
                    {
                        tempX 
    = parentNode.LeftChild;
                        
    if (tempX != null && tempX.Color == NodeColor.Red)
                        {
                            tempX.Color 
    = NodeColor.Black;
                            parentNode.Color 
    = NodeColor.Red;
                            RightRotate(parentNode);
                        }
                        
    else
                        {
                            
    if ((tempX.LeftChild == null && tempX.RightChild == null)
                               
    || (tempX.LeftChild.Color == NodeColor.Black && tempX.RightChild.Color == NodeColor.Black))
                            {
                                tempX.Color 
    = NodeColor.Red;
                                node 
    = parentNode;
                                parentNode 
    = node.ParentNode;
                            }
                            
    else
                            {
                                
    if (tempX.RightChild == null || tempX.RightChild.Color == NodeColor.Black)
                                {
                                    
    if (tempX.RightChild != null)
                                    {
                                        tempX.RightChild.Color 
    = NodeColor.Black;
                                        tempX.Color 
    = NodeColor.Red;
                                    }
                                    LeftRotate(tempX);
                                    tempX 
    = parentNode.LeftChild;
                                }
                                tempX.Color 
    = parentNode.Color;
                                parentNode.Color 
    = NodeColor.Black;
                                tempX.LeftChild.Color 
    = NodeColor.Black;
                                RightRotate(parentNode);
                                node 
    = root;
                            }
                        }
                    }
                }
                node.Color 
    = NodeColor.Black;
            }

            
    /// <summary>
            
    /// Right rotate the node, used when fix up tree property
            
    /// </summary>
            
    /// <param name="node"></param>
            private void RightRotate(RedBlackTreeNode<S> node)
            {
                
    if (node.LeftChild == null)
                    
    return;
                RedBlackTreeNode
    <S> child = node.LeftChild;
                
    if (node.ParentNode != null)
                {
                    
    if (node.ParentNode.LeftChild != null && node.ParentNode.LeftChild == node)
                    {
                        node.ParentNode.LeftChild 
    = child;
                    }
                    
    else
                    {
                        node.ParentNode.RightChild 
    = child;
                    }
                }
                
    else
                {
                    node.LeftChild.ParentNode 
    = null;
                }
                node.LeftChild 
    = child.RightChild;
                child.RightChild 
    = node;
                RecheckRoot();
            }

            
    /// <summary>
            
    /// Left rotate the node, used when fix up tree property
            
    /// </summary>
            
    /// <param name="node"></param>
            private void LeftRotate(RedBlackTreeNode<S> node)
            {
                
    if (node.RightChild == null)
                    
    return;

                RedBlackTreeNode
    <S> child = node.RightChild;
                
    if (node.ParentNode != null)
                {
                    
    if (node.ParentNode.LeftChild != null && node.ParentNode.LeftChild == node)
                    {
                        node.ParentNode.LeftChild 
    = child;
                    }
                    
    else
                    {
                        node.ParentNode.RightChild 
    = child;
                    }
                }
                
    else
                {
                    node.RightChild.ParentNode 
    = null;
                }
                node.RightChild 
    = child.LeftChild;
                child.LeftChild 
    = node;
                RecheckRoot();
            }

            
    /// <summary>
            
    /// the rotation may change the root, check and reset the root node.
            
    /// </summary>
            private void RecheckRoot()
            {
                
    while (root.ParentNode != null)
                {
                    root 
    = root.ParentNode;
                }
            }
        }
    }
    RedBlackTreeNode.cs
    using System;

    namespace Cn.Linc.Algorithms.BasicStructure
    {
        
    public class RedBlackTreeNode<T> where T : IComparable

        {
            
    private T value;

            
    public T Value
            {
                
    get { return this.value; }
                
    set { this.value = value; }
            }
            
    private NodeColor color;

            
    public NodeColor Color
            {
                
    get { return color; }
                
    set { color = value; }
            }
            
    private RedBlackTreeNode<T> leftChild;

            
    public RedBlackTreeNode<T> LeftChild
            {
                
    get { return leftChild; }
                
    set
                {
                    
    if (value != null)
                        value.ParentNode 
    = this;
                    leftChild 
    = value; 
                }
            }
            
    private RedBlackTreeNode<T> rightChild;

            
    public RedBlackTreeNode<T> RightChild
            {
                
    get { return rightChild; }
                
    set 
                {
                    
    if (value != null)
                        value.ParentNode 
    = this;
                    rightChild 
    = value; 
                }
            }

            
    private RedBlackTreeNode<T> parentNode;

            
    public RedBlackTreeNode<T> ParentNode
            {
                
    get { return parentNode; }
                
    set { parentNode = value; }
            }

            
    public RedBlackTreeNode(T nodeValue)
            {
                value 
    = nodeValue;
                color 
    = NodeColor.Red;
            }
        }
    }
  • 相关阅读:
    依次逐个亮灯并且每次只能亮一个灯的跑马灯程序
    逐个点亮LED灯,再逐个熄灭LED灯的跑马灯程序---基于74HC595移位锁存器,程序框架用switch语句
    把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式
    两片联级74HC595驱动16个LED灯的基本驱动程序
    树莓派
    Linux I2C驱动
    转:使用 /proc 文件系统来访问 Linux 内核的内容
    转: 使用 /sys 文件系统访问 Linux 内核
    树梅派 -- 通过/sys读写ADC芯片 pcf8591
    树莓派 -- oled 续(2) python
  • 原文地址:https://www.cnblogs.com/SharpDeveloper/p/1918407.html
Copyright © 2020-2023  润新知