比二分法更快的搜索算法

HashTree介绍:

最近在复习补充数据结构及算法知识,因为不是计算机专业,底子薄,没办法。虽然写了几年代码,但遇到问题时,总是感觉抓不住核心,无法高效的解决问题。尤其是看了侯捷老师的课程后,更加感慨。老师曾说:勿以流沙建高楼!!!顿时奉为至理名言。

好了,进入主题,复习算法章节时,看到二分法,据我浅薄的理解,无非就几步而已。按照大小给数据排序,然后按照树结构对数据进行组织,当然最好采用平衡树结构,这样会极大的缩小搜索次数。我突然冒出个想法,是否有比二分法更快的搜索算法呢?我们都知道,二分法已经达到Log2 n的时间复杂度了,已经非常快了。那么真的会有比二分法更快的方法吗,我非常好奇?直到看到了哈希算法!!!

对于哈希算法假设大家都比较熟悉了,不熟悉也没关系,百度上文章很多,稍微看下就行,简单来说,就是把数据按照一个固定的算法进行分类,取数据的时候也按照相同的算法进行查找,相比于遍历搜索节省了大量的查找次数和查找时间。大家如果想做更详细的了解的可以直接百度,我就不做过多介绍了。

重点来了!!!

能否利用哈希算法提高二分查找的效率呢?我们知道,二分法,每查找一次,能够排除近乎一半的数据(平衡二叉树),如果结合哈希算法,每一次查找,应该可以排除更多的数据。假如我有9个数,1 2 3 4 5 6 7 8 9 ,要查找2。根据二分法,先找到中间节点5,查找目标2小于5,所以在左子节点继续找,这时找到节点3,目标2仍然小于3,继续查找左子节点2,找到了!用了3次查找。

如果利用hash算法,这9个数按照顺序依次存放在一个数组中。那个固定的分类和查找算法就是,数组首地址 + sizeof(int) * (2 - 1)。这里的2代表你要查找的数字。

hash算法的弊端在于,如果数据过于庞大,hash算法需要的固定的分类算法也会相对比较复杂,且hash冲突也会频繁发生,当有多个值通过分类算法得到的结果相同,就会产生冲突。怎么去解决冲突,不在此章节展开讲,我所常见的就是在hash表每个位置后维护一张链表,有冲突的key值会依次放入链表中以待后续查询。

这样的hash结构,我称之为单次哈希。随便取的名字,大家不必介怀,最重要的是引出下面的多次hash结构。。。

俗话说,数不如表,表不如图,下面我给大家画个图

此图中的数据,我们可以暂时理解成一个节点数组,以及存放一个值的空间,和上面的例子一样。我将其作为N叉树中的一个节点Node,N = 10,分叉数量和数组中元素个数相同。 树结构如下图

下面还有,我就不画了,本质就是一个N叉树,每个树节点里维护一个Node数组以及一个值对象而已。结构很简单,奈何画图水平有限,见谅。。。

那么如何存放数据呢?初始树结构里只有一个根节点,节点里面数组为null,只有一个值为-1(-1为标识非法数值类型,默认无效值)。

先放一个1进去,首先计算1 % 10的值,等于1。这时找到第一个节点,也就是根节点,为根节点中的数组开辟空间,也就是什么时候用什么时候开辟,默认节点数组都是null,这样更节省内存。

 然后在开辟空间的数组中把1放到数组下标为1的位置。以此类推,2会放到下标为2的位置。等等

好,这时候我们已经放了一个元素进去。如下图

那么继续,再放一个进去,例如2,计算2 % 10,等于2, 此时将2放到根节点中数组下标为2的位置,如下图

继续,放数字12进去,个位数字是2,十位数字是1,那么该怎么放呢?

首先判断个位,个位数字是2,就应该放到数组下标为2的位置,但是这个位置已经有值了,2.

好,在这个有值的节点中,开辟这个节点中数组的空间,将这个数组中下标为1(12的十位数字)的节点处放入12这个值。如下图

 后面依次类推。所有的数据均按照此方法进行放置。

大致原则,将数字按照位数分组,个位数字是几,就找到根节点的数组中的第几个位置。继续计算十位数字是几,寻找到子节点中数组的第几个位置的孙节点,继续计算,一直到遍历完所有的位数,或者在找到一个空位置处存放这个数。

看到这里如果你晕了,没关系。只要你懂了如何在树结构中查找数据,你就能理解为什么要按照上面的方式存储数据了。

查找数据:

例如,在这个树结构中查找 1653564

首先看个位数字4,拿到根节点,找到节点中的数组下标为4的节点,比对这个节点中的值是否等于1653564,假如不等,继续计算十位数字6,在上面找到的下标为4的节点中,拿到这个节点的数组数据,找到下标为6的节点,对比其值是否等于1653564,如果不等,继续找百位数字5,继续拿子节点做对比。直到找到节点值等于1653564的节点。

也就是说,若查询1653564这个值,最多仅需要比对7次即可。也就是这个数有多少位,我们最多也就比对多少次。

优化:

上面的示例中,我是以十进制的方式演示的,实际中为了更快的进行取模运算和计算各分位数值。

我采取的16 * 16进制进行数据存储,也就是一个数组中存放256个节点。这样能更好的减少查询次数。当然也可以存放16个节点。

那么这种存储数据的方式的优缺点是什么呢?我总结一下:

优点:

1、当数据量过于庞大时,比如达到亿级,十亿,百亿级时(假设内存中能够存储这么多数据)。此方法查询数据的次数明显少于二分法。根据我自己的测试结果显示,50万条数据,二分法查找需要22次左右,HashTree方法只需要3次左右(HashTree是我自己对这种存储结构的暂时命名,且3次是我优化了这个结构的查询次数,后面会讲到优化的方法),由于电脑支持不了千万级及以上的数据,所以只测试到了50w级别。

 2、单次查询,二分法只做了比较大小,然后根据子节点地址取值操作,而hashTree方法先做取余运算,然后根据余数寻址取值。按照道理来讲,二分法查询一次的速度更快。但通过我的测试,对二分法和hashtree方法都做了一亿次的重复查询并取值操作,hashtree方法居然更快,这里我也没搞懂,稍后我会贴代码,大家也可以看看。

缺点:

1、hashtree结构占用空间较大,最不利情况,hashtree应该比二叉树结构多占N倍的空间,N为每个节点中数组的个数。

2、hashtree结构空间利用率不高,数据越紧密,hashtree的空间利用率越高,最不利就是N倍。最不利的数据就像存储1 11 111 1111 11111...这种情况,当然这种情况很少。

3、目前来说,办公型普通配置电脑,达不到上亿级的内存数据存储,即使hashtree查询次数明显少于二分法,也仅仅是3次查询和22次查询的区别。一闪而逝,都用不了1ms。查询效率相当。

4、hash树目前仅支持对整形数据的操作,如果分正负值的话,也可以分两棵树去存储。如果存储小数值,可将小数乘以10的N次方后转为整数,进行存储。二分法则比较简单,只要能够比较大小,任何数据都可以作为实际值存储在节点中。

总结

由于目前计算机硬件的限制,hashtree并无明显优势,但胜在潜力。在日新月异的技术更新的年代,可能在某些领域会逐渐凸显优势。尤其是现在各行各业都在进行数字化转型,数据量也是呈指数级增长。在这些海量的数据中,能够速度更快的查询数据也是衡量技术指标的一个必不可少的条件。我相信hashtree也能在未来的某一天内发挥它的作用。

最后,本文仅为作者抛砖引玉,欢迎大家批评指正,当然更多的还是希望读者看到后会有一些启发。有疑问也可以联系作者qq 3535413812。谢谢大家!

代码:

using HashTreeTest.HashTree;
using HashTreeTest.RedBlackTree;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace HashTreeTest
{
    public static class Demo
    {
        public static void Main()
        {
            Console.WriteLine("****************测试开始****************");
            int count = 10000000;
            int find  = 0x20000;
            HashTreeAlgorithm.HashTree hashTree = new HashTreeAlgorithm.HashTree();
            RB_Tree avlTree = new RB_Tree();
            #region treetest
            //hash树
            {
                Console.WriteLine($"开始构造Hash树");
                var watch = new Stopwatch();
                watch.Start();
                for (int i = 0; i < count; i++)
                {
                    hashTree.Add(i);
                }
                watch.Stop();
                var detalTime = watch.Elapsed.TotalMilliseconds;
                Console.WriteLine($"构造Hash树完成");
                Console.WriteLine($"用时:{detalTime}ms");
                Console.WriteLine($"开始查找{find}");
                var watch2 = new Stopwatch();
                watch2.Start();
                var result = hashTree.Find(find);
                watch2.Stop();
                var detalTime2 = watch2.Elapsed.Ticks;
                Console.WriteLine($"查找次数{hashTree.LoopCount}");
                Console.WriteLine($"找到结果{result}");
                ConsoleEx.WriteLine(ConsoleColor.Green, $"用时:{detalTime2}个ticks");
            }
            //AVL树
            {
                Console.WriteLine($"开始构造AVL树");
                var watch = new Stopwatch();
                watch.Start();
                for (int i = 0; i < count; i++)
                {
                    avlTree.Insert(i);
                }
                watch.Stop();
                var detalTime = watch.Elapsed.TotalMilliseconds;
                Console.WriteLine($"构造AVL树完成");
                Console.WriteLine($"用时:{detalTime}ms");
                Console.WriteLine($"开始查找{find}");
                var watch2 = new Stopwatch();
                watch2.Start();
                var node = avlTree.Find(find);
                watch2.Stop();
                var detalTime2 = watch2.Elapsed.Ticks;
                Console.WriteLine($"查找次数{avlTree.LoopCount}");
                Console.WriteLine($"找到结果{node.data}");
                ConsoleEx.WriteLine(ConsoleColor.Green, $"用时:{detalTime2}个ticks");
            }

            #endregion
            Console.WriteLine("****************测试结束****************");
            Console.ReadKey();
        }
    }

    public static class ConsoleEx
    {
        public static void WriteLine(ConsoleColor textColor, string text)
        {
            var foreColor = Console.ForegroundColor;
            Console.ForegroundColor = textColor;
            Console.WriteLine(text);
            Console.ForegroundColor = foreColor;
        }

        public static void Write(ConsoleColor textColor, string text)
        {
            var foreColor = Console.ForegroundColor;
            Console.ForegroundColor = textColor;
            Console.Write(text);
            Console.ForegroundColor = foreColor;
        }
    }

namespace HashTreeAlgorithm
    {
        /// <summary>
        /// 一个储存单元是8位,一个byte,内部数组的容量
        /// </summary>
        public class HashTree
        {
            public int LoopCount = 0;
            public Node Root { get; set; } = new Node(-1);
            public void Add(int data/*不验证data的有效性,只要你add了,就说明这个数是一个可以插进来的数*/)
            {

                var lastNum = data & 0xff;
                if (Root.Nodes == null) { Root.Nodes = new Node[Util.Capacity]; }
                var newNode = new Node(data);
                if (Root.Nodes[lastNum] == null)
                {
                    Root.Nodes[lastNum] = newNode;
                    newNode.Parent = Root;
                }
                else
                {
                    Root.Nodes[lastNum].AddNode(newNode);
                }
                return;
            }

            public int Find(int data)
            {
                var temp = data;
                var current = Root;
                while (current.Value != data)
                {
                    LoopCount++;
                    if (temp == 0x0) { return -1; }
                    var lastDigit = temp & 0xff;
                    current = current.Nodes[lastDigit];
                    if (current == null) { return -1; }
                    temp >>= Util.ShiftBit;
                }
                return current.Value;
            }

            public int Find2(int data, int count)
            {
                var temp = data;
                var current = Root;
                for (int i = 0; i < 100000000; i++)
                {
                    LoopCount++;
                    var lastDigit = 0x15236548 & 0xff;
                    var n = current.Nodes[lastDigit];
                    temp >>= Util.ShiftBit;
                }
                return current.Value;
            }

            public void Clear() { Root = new Node(-1); }
        }
        public class Node
        {
            public int Value = -1;

            public Node Parent = null;

            public Node[] Nodes = null;

            public Node(int value) { Value = value; }

            public int GetGradeLevel()
            {
                var grade = 0;//从0级开始
                var currentNode = this;
                while (currentNode.Parent != null)
                {
                    currentNode = currentNode.Parent;
                    grade++;
                }
                return grade;
            }

            public void AddNode(Node insertNode)
            {
                if (insertNode.Value == this.Value) { return; }
                var grade = this.GetGradeLevel();
                if (insertNode.Value == grade)
                {
                    if (this.Value == -1)
                    {
                        this.Value = insertNode.Value;
                    }
                    return;
                }

                var index = insertNode.Value.GetDigit(grade);//要插入到哪个位置的索引

                //1、如果当前节点Value为空,则找对应Index下的子节点,递归判断
                if (Value == -1)
                {
                    var childNodes = this.Nodes.ToList().FindAll(x => x != null);
                    var childValues = childNodes.Select(x => //找childNodes中的两个子节点的有效value值
                    {
                        if (x.Value != -1) { return x.Value; }
                        Node child = x;
                        while (child.Value == -1)
                        {
                            var childs = child.Nodes.ToList().FindAll(y => y != null);
                            var validChild = childs.Find(z => z.Value != -1);
                            if (validChild != null) { return validChild.Value; }
                            child = childs.FirstOrDefault();
                        }
                        return -1;
                    });
                    if (childValues == null || childValues.Count() < 2) { throw new Exception("节点数据错误:未找到两个以上节点有效Value值"); }
                    //如果新节点 是 当前节点下两个及以上子sun节点 的 祖父节点,则新节点 替换 当前节点
                    if (Util.IsParent(childValues.First(), insertNode.Value) && Util.IsParent(childValues.Last(), insertNode.Value))
                    {
                        this.Value = insertNode.Value;
                    }
                    else if (this.Nodes[index] == null) //如果所需插入位置无节点,直接插入
                    {
                        insertNode.Parent = this;
                        this.Nodes[index] = insertNode;
                    }
                    else//如果所需插入位置有节点,递归加入
                    {
                        Nodes[index].AddNode(insertNode);
                    }
                    return;
                }
                //2、如果当前节点Value不为空,则根据父子关系或者兄弟关系重新进行组织
                else if (Util.IsSon(Value, insertNode.Value))//插入值为子孙节点
                {
                    CreateSonNode(insertNode, index);
                }
                else if (Util.IsParent(Value, insertNode.Value)) //插入值为祖父节点
                {
                    CreateFatherNode(insertNode);
                }
                else //出五服了
                {
                    CreateBrotherNode(insertNode);
                }
                return;
            }

            private void CreateBrotherNode(Node insertNode)
            {
                var currentGrade = this.GetGradeLevel();
                var currentIndex = this.Value.GetDigit(currentGrade - 1);//所在父节点的子节点数组索引
                var newNode = new Node(-1);
                this.Parent.Nodes[currentIndex] = newNode;
                newNode.Parent = this.Parent;
                this.Parent = newNode;
                insertNode.Parent = newNode;
                newNode.Nodes = new Node[Util.Capacity];
                var index1 = insertNode.Value.GetDigit(currentGrade);
                newNode.Nodes[index1] = insertNode;
                var index2 = this.Value.GetDigit(currentGrade);
                newNode.Nodes[index2] = this;
            }

            private void CreateFatherNode(Node insertNode)
            {
                var currentGrade = this.GetGradeLevel();
                var currentIndex = this.Value.GetDigit(currentGrade - 1);//所在父节点的子节点数组索引

                var parent = insertNode;
                parent.Parent = this.Parent;
                this.Parent = parent;

                if (parent.Nodes == null) { parent.Nodes = new Node[Util.Capacity]; }
                parent.Nodes[currentIndex] = this;
                var index = this.Value.GetDigit(currentGrade);//所在父节点的子节点数组索引
                parent.Parent.Nodes[index] = this;
                if (parent.Value > this.Value || parent.Value > insertNode.Value)
                {
                    throw new Exception("父节点数据错误:父节点Value大于子节点Value");
                }
            }

            private void CreateSonNode(Node insertNode, int index)
            {
                var son = insertNode;
                if (this.Nodes == null) { this.Nodes = new Node[Util.Capacity]; }
                if (this.Nodes[index] == null)
                {
                    son.Parent = this;
                    this.Nodes[index] = son;
                }
                else
                {
                    this.Nodes[index].AddNode(insertNode);
                }
                if (this.Value > insertNode.Value)
                {
                    throw new Exception("父节点数据错误:父节点Value大于子节点Value");
                }
            }
        }
    }


    namespace HashTree
    {
        public static class Util
        {
            public const int Capacity = 0x100; //16进制数字

            public const int ShiftBit = 0x8; //右移时的位数

            public const int FilterBit = 0xff;

            /// <summary>
            /// 返回指定位数的数字
            /// </summary>
            /// <param name="number">0x1582</param>
            /// <param name="digitIndex">0返回0x82,1返回0x15</param>
            /// <returns></returns>
            public static int GetDigit(this int number, int digitIndex)
            {
                if (number < 0) { return -1; }
                number >>= digitIndex * ShiftBit;
                var result = number & FilterBit;
                return result;
            }

            public static bool IsSon(int parent, int son)
            {
                return (parent & son) == parent;
            }

            public static bool IsParent(int son, int parent)
            {
                return (parent & son) == parent;
            }

        }
    }

namespace RedBlackTree
    {
        public class TreeNode
        {
            public int data;
            public TreeNode left;
            public TreeNode right;
            public TreeNode parent;

            public bool color;

            public TreeNode(int data)
            {
                this.data = data;
                this.color = false;
            }
        }
        public class RB_Tree
        {
            public const bool RED = false;
            public const bool BLACK = true;

            public TreeNode root = null;
            public void Insert(int item)
            {
                if (root == null)
                {
                    //注意,根节点为黑色
                    root = new TreeNode(item);
                    Black(root);
                }
                else
                {
                    //这一步只完成插入操作,与二叉查找的插入是一样的
                    var newnode = Inserts(item);
                    //重点在于这一步,看节点是否需要调整
                    InsertFixUp(newnode);
                }
            }
            public TreeNode Inserts(int item)
            {
                TreeNode node = root;
                TreeNode newnode = new TreeNode(item);
                while (true)
                {
                    if (item > node.data)
                    {
                        if (node.right == null)
                        {
                            //注意父子关系要确定
                            newnode.parent = node;
                            node.right = newnode;
                            break;
                        }
                        node = node.right;
                    }
                    else if (item < node.data)
                    {
                        if (node.left == null)
                        {
                            newnode.parent = node;
                            node.left = newnode;
                            break;
                        }
                        node = node.left;
                    }
                }
                return newnode;
            }
            private void InsertFixUp(TreeNode node)
            {
                TreeNode parent = node.parent;
                if (parent == null)
                {
                    Black(node);
                    return;
                }
                if (IsBlack(parent)) return;

                TreeNode uncle = Sibling(parent);
                TreeNode grand = parent.parent;
                if (IsRed(uncle))//叔叔节点是黑色
                {
                    Black(parent);
                    Black(uncle);
                    InsertFixUp(Red(grand));
                    return;//这里直接返回,因为下面处理的是祖父节点的调整,与自己这个节点已经无关了
                }
                if (IsLeftChild(parent))
                {
                    if (IsLeftChild(node))
                    {
                        Black(parent);
                        Red(grand);
                        RightRotate(grand);
                    }
                    else
                    {
                        Black(node);
                        Red(grand);
                        LeftRotate(parent);
                        RightRotate(grand);
                    }
                }
                else
                {
                    if (IsLeftChild(node))
                    {
                        Black(node);
                        Red(grand);
                        RightRotate(parent);
                        LeftRotate(grand);
                    }
                    else
                    {
                        Black(parent);
                        Red(grand);
                        LeftRotate(grand);
                    }
                }
            }
            public void Remove(int data)
            {
                TreeNode node = Find(data);
                Remove(node);
            }
            private void Remove(TreeNode node)
            {
                if (node == null)
                    return;
                if (node.left != null && node.right != null)
                {
                    TreeNode s = FindNext(node);
                    node.data = s.data;
                    node = s;
                }
                TreeNode replacement = node.left != null ? node.left : node.right;
                if (replacement != null)
                {
                    replacement.parent = node.parent;
                    if (node.parent == null)
                        root = replacement;
                    else if (node == node.parent.left)
                        node.parent.left = replacement;
                    else
                        node.parent.right = replacement;
                    RemoveFixUp(node, replacement);
                }
                else if (node.parent == null)//是叶子结点,并且是根节点
                {
                    root = null;
                    //RemoveFixUp(node, null);
                }
                else//是叶子结点,但不是根节点
                {
                    if (node == node.parent.right)
                        node.parent.right = null;
                    else
                        node.parent.left = null;
                    RemoveFixUp(node, null);
                }
            }
            private void RemoveFixUp(TreeNode node, TreeNode replacement)
            {
                //1、如果删除的是红色节点
                if (IsRed(node)) return;
                //2、如果删除的是黑色节点,用于取代node的节点是红色
                if (IsRed(replacement))
                {
                    Black(replacement);
                    return;
                }
                //3、如果删除的是黑色节点,孩子都是黑色(或者null)
                TreeNode parent = node.parent;
                //3.1、如果删除的是根节点,直接返回
                if (parent == null) return;
                //获取删除节点的兄弟节点
                bool left = parent.left == null || IsLeftChild(node);//判断删除的是父节点的左子节点还是右子节点
                TreeNode sibling = left ? parent.right : parent.left;
                if (left)//被删除的节点在右边,兄弟节点在左边
                {
                    if (IsRed(sibling))//兄弟节点是红色情况
                    {
                        Black(sibling);
                        Red(parent);
                        LeftRotate(parent);

                        sibling = parent.right;//重新指定兄弟节点
                    }
                    //能来到这里。兄弟节点必是黑色了,处理黑色兄弟的情况
                    if (IsBlack(sibling.left) && IsBlack(sibling.right))
                    {
                        bool parentBlack = IsBlack(parent);
                        Red(sibling);
                        Black(parent);
                        if (parentBlack)
                        {
                            RemoveFixUp(parent, null);
                        }
                    }
                    else//能来到这里,说明兄弟中至少有一个红色子节点
                    {
                        if (IsBlack(sibling.right))
                        {
                            RightRotate(sibling);
                            sibling = parent.right;//兄弟节点变了,这里要重新转换
                        }
                        Color(sibling, ColorOf(parent));
                        Black(sibling.right);
                        Black(parent);
                        LeftRotate(parent);
                    }
                }
                else
                {
                    if (IsRed(sibling))//兄弟节点是红色情况
                    {
                        Black(sibling);
                        Red(parent);
                        RightRotate(parent);

                        sibling = parent.left;//重新指定兄弟节点
                    }
                    //能来到这里。兄弟节点必是黑色了,处理黑色兄弟的情况
                    if (IsBlack(sibling.left) && IsBlack(sibling.right))
                    {
                        bool parentBlack = IsBlack(parent);
                        Red(sibling);
                        Black(parent);
                        if (parentBlack)
                        {
                            RemoveFixUp(parent, null);
                        }
                    }
                    else//能来到这里,说明兄弟中至少有一个红色子节点
                    {
                        if (IsBlack(sibling.left))
                        {
                            LeftRotate(sibling);
                            sibling = parent.left;//兄弟节点变了,这里要重新转换
                        }
                        Color(sibling, ColorOf(parent));
                        Black(sibling.left);
                        Black(parent);
                        RightRotate(parent);
                    }
                }
            }
            public TreeNode FindNext(TreeNode root)
            {
                if (root == null)
                    return null;
                if (root.right == null)
                    return null;
                TreeNode current = root.right;
                while (current != null)
                {
                    if (current.left != null)
                    {
                        current = current.left;
                    }
                    else
                        break;
                }
                return current;
            }
            public int LoopCount = 0;
            public TreeNode Find(int data)
            {
                TreeNode current = root;
                while (current != null)
                {
                    LoopCount++;
                    //Find1(50);
                    if (data < current.data)
                        current = current.left;
                    else if (data > current.data)
                        current = current.right;
                    else
                        return current;
                }
                return null;
            }
            private void LeftRotate(TreeNode node)
            {
                TreeNode parent = node.parent;
                TreeNode rightChild = node.right;
                TreeNode grandLeftChild = rightChild.left;

                node.parent = rightChild;
                rightChild.left = node;
                rightChild.parent = parent;
                if (parent != null)
                {
                    if (parent.left == node)
                    {
                        parent.left = rightChild;
                    }
                    else
                    {
                        parent.right = rightChild;
                    }
                }
                else//如果父节点是空,说明是根节点,让root指向旋转后的父节点
                {
                    root = rightChild;
                }
                node.right = grandLeftChild;
                if (grandLeftChild != null)
                {
                    grandLeftChild.parent = node;
                }
            }
            private void RightRotate(TreeNode node)
            {
                TreeNode parent = node.parent;
                TreeNode leftChild = node.left;
                TreeNode grandRightChild = leftChild.right;

                node.parent = leftChild;
                leftChild.right = node;
                leftChild.parent = parent;
                if (parent != null)
                {
                    if (parent.left == node)
                    {
                        parent.left = leftChild;
                    }
                    else
                    {
                        parent.right = leftChild;
                    }
                }
                else//如果父节点是空,说明是根节点,让root指向旋转后的父节点
                {
                    root = leftChild;
                }
                node.left = grandRightChild;
                if (grandRightChild != null)
                {
                    grandRightChild.parent = node;
                }
            }
            //染色
            private TreeNode Color(TreeNode node, bool color)
            {
                if (node == null)
                    return node;
                node.color = color;
                return node;
            }
            //获取颜色
            private bool ColorOf(TreeNode node)
            {
                if (node == null)
                    return BLACK;
                return node.color == RED ? RED : BLACK;
            }
            //染成红色
            private TreeNode Red(TreeNode node)
            {
                return Color(node, RED);
            }
            //染成黑色
            private TreeNode Black(TreeNode node)
            {
                return Color(node, BLACK);
            }
            //判断是否为红色
            private bool IsRed(TreeNode node)
            {
                return ColorOf(node) == RED;
            }
            //判断是否为黑色
            private bool IsBlack(TreeNode node)
            {
                return ColorOf(node) == BLACK;
            }
            //判断是不是父亲的左孩子
            private bool IsLeftChild(TreeNode node)
            {
                return node.parent != null && node.parent.left == node;
            }
            //判断是不是父亲的右孩子
            private bool IsRightChild(TreeNode node)
            {
                return node.parent != null && node.parent.right == node;
            }
            //获取兄弟节点
            private TreeNode Sibling(TreeNode node)
            {
                if (IsLeftChild(node))
                {
                    return node.parent.right;
                }
                if (IsRightChild(node))
                {
                    return node.parent.left;
                }
                return null;
            }
            public void PreOrder(TreeNode node)
            {
                Stack<TreeNode> stack = new Stack<TreeNode>();
                TreeNode current = node;
                while (current != null || stack.Count > 0)
                {
                    while (current != null)
                    {
                        string color = current.color == RED ? "R" : "B";
                        Console.Write(color + current.data + "  ");
                        stack.Push(current);
                        current = current.left;
                    }
                    if (stack.Count > 0)
                    {
                        current = stack.Pop().right;
                    }
                }
            }
        }
    }

}
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值