算法笔记(红黑树)

国密GmSSL v2版本命令行方式生成国密sm2私钥、公钥、签名和验证签名 GmSSL是国密算法的工具库(主要包含SM2、SM3、SM4和国密SSL证书生成等功能),项目本身是OpenSSL的分支,但是截至文章发布为止,OpenSSL主分支的国密算法并不完善,目前并不支持签名和解签,所以国密算法这块还是需要使用GmSSL工具库。网上现在并没有v2版本的GmSSL可用的命令行文章,本章用于记录这些命令。本文原创自csdn博客,其他网站看到这篇文章都是盗,版,爬。虫。网站,支持原创,远离盗版。 阅读详情

前面的博文分析了一般查找树的性质,理论上来讲,可以构造m阶完全树,但这种结构,会导致调整过于频繁,所以保持相对平衡就成了一种策略。红黑树,B树都是这种考虑。分析这些树(红黑树,AVL,B树)等,一个重要的地方就是我们所做的大部分工作的目标就是需要保持树在一定程度上的平衡。

下面是红黑树常见操作的实现:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AlbertAlgorithms
{
    /// <summary>
    /// 节点颜色枚举
    /// </summary>
    public enum RBTreeNodeColor
    {
        Red,
        Black
    }
    /// <summary>
    /// 红黑树节点
    /// </summary>
    public class RBTreeNode
    {
        public int Key { get; set; }
        public RBTreeNode Left { get; set; }
        public RBTreeNode Right { get; set; }
        public RBTreeNode Parent { get; set; }
        public RBTreeNodeColor NodeColor { get; set; }
    }
    /// <summary>
    /// 红黑树
    /// </summary>
    public class RBTree
    {
        /// <summary>
        /// 空节点,充当哨兵
        /// </summary>
        public static readonly RBTreeNode NullNode=new RBTreeNode();
        /// <summary>
        /// 静态构造函数,哨兵为黑色.
        /// </summary>
        static RBTree()
        {
            NullNode.NodeColor = RBTreeNodeColor.Black;
        }
        /// <summary>
        /// 根节点,默认为NullNode.
        /// </summary>
        public RBTreeNode Root = NullNode;
        /// <summary>
        /// 插入节点,这里假设了所有的节点key不相同.
        /// </summary>
        /// <param name="Node"></param>
        public void InsertNode(RBTreeNode Node)
        {
            ///寻找插入节点的插入点(父节点)theY.TheX是循环中间变量.
            RBTreeNode theY = NullNode;
            RBTreeNode theX = Root;
            //注意,如果不为空,则找到的插入节点一定是最底层内节点,仅有空字节点(哨兵节点).
            //这也是红黑树不是高度平衡树的一个重要原因.但这样简化了插入,不用判断补缺.
            while (theX != NullNode)
            {
                theY = theX;
                if (Node.Key > theX.Key)
                {
                    theX = theX.Right;//此处错误
                }
                else
                {
                    theX = theX.Left;
                }
            }
            //将插入节点的父节点指向theY.
            Node.Parent = theY;
            //如果theY为空,则原来是空树,则新插入的节点是根节点.
            if (theY == NullNode)
            {
                Root = Node;
            }
            else
            {
                //如果有根节点,与theY的Key比较,大于则作为右子节点,小于则
                //作为左节点.
                if (Node.Key > theY.Key)
                {
                    Node.Parent = theY.Right; //
                }
                else
                {
                    Node.Parent = theY.Left;
                }
            }
            //开始插入的节点都在非空叶子节点上,将空节点作为其两个子节点.
            Node.Right = NullNode;
            Node.Left = NullNode;
            //颜色置为红,然后整理.
            Node.NodeColor = RBTreeNodeColor.Red;
            RBInsertFixup(Node);
        }
        /// <summary>
        /// 红黑树的插入整理,以保持红黑树性质:非红即白;根和叶子黑;相邻节点不能同为红;
        /// 所有从根到叶子路径上的黑节点(黑度)相同.这里的相邻只会是父子节点间,书上的定义是
        /// 红节点的两个孩子节点都是黑的,表达是等价的.从根到叶子节点看做是树的路径,则路径
        /// 上红节点不能相邻.
        /// </summary>
        /// <param name="Node"></param>
        private void RBInsertFixup(RBTreeNode Node)
        {
            //因为当前节点为红色,从下向根方向整理,如果当前节点的父节点为红色,则违反了红黑树的性质,
            //就需要不断整理,直到当前整理节点的父节点是黑色为止.整理一定会有结束条件,
            //因为根节点肯定为黑。
            while (Node.Parent.NodeColor == RBTreeNodeColor.Red)
            {
                //如果父节点为红色,则爷节点必为黑色(红黑树性质)。
                //如果当前节点的父节点是左孩子
                if (Node.Parent == Node.Parent.Parent.Left)
                {
                    //找到其叔父节点.
                    RBTreeNode theY = Node.Parent.Parent.Right;
                    //如果叔父节点是红色节点,而爷节点为黑色节点。形式就是爷节点为黑,父辈节点为红,由于当前节点为红,
                    //父节点必须改为黑色。而且这种改变不能影响黑度(所有从根到叶子节点的路径中黑节点数相等),那么改变的策略
                    //就是将爷节点变为红色,父辈节点变为黑色,这种改变显然没有改变路径上的黑度。但因为爷节点变为了红色,可能
                    //会导致红黑树性质的改变,就需要继续整理,因此需将整理节点上移到爷节点,继续整理。
                    if (theY.NodeColor == RBTreeNodeColor.Red)
                    {
                        Node.Parent.NodeColor = RBTreeNodeColor.Black;
                        theY.NodeColor = RBTreeNodeColor.Black;
                        Node.Parent.Parent.NodeColor = RBTreeNodeColor.Red;
                        Node = Node.Parent.Parent;
                    }
                    //如果叔父节点是黑色,爷节点也为黑色,父节点因为要改成黑节点,就增加了当前节点路径上的黑度。因此处理就稍微复杂些。
                    else
                    {
                        //如果当前节点是右孩子,先左旋。因为轴是当前节点和父节点,都为红色,因此左旋不会改变黑度,这很关键。
                        if (Node == Node.Parent.Right)
                        {
                            Node = Node.Parent;
                            LeftRotate(Node);
                        }
                        //将父节点改为黑节点,爷节点改为红色节点,当前节点路径上的黑度没变,但叔父路径上的黑度被减了1,为了保持黑度不变,因此需要右旋
                        //其实就是将父节点上升到爷节点,原来的爷节点降为叔父节点,这样黑度就平衡了。
                        Node.Parent.NodeColor = RBTreeNodeColor.Black;
                        Node.Parent.Parent.NodeColor = RBTreeNodeColor.Red;
                        RightRotate(Node.Parent.Parent);
                    }
                }//如果当前节点的父节点是右孩子.因为是对称情况,所以逻辑处理与前面类似.
                else
                {
                    //找到其叔父节点.
                    RBTreeNode theY = Node.Parent.Parent.Left;
                    if (theY.NodeColor == RBTreeNodeColor.Red)
                    {
                        Node.Parent.NodeColor = RBTreeNodeColor.Black;
                        theY.NodeColor = RBTreeNodeColor.Black;
                        Node.Parent.Parent.NodeColor = RBTreeNodeColor.Red;
                        Node = Node.Parent.Parent;
                    }
                    else
                    {
                        if (Node == Node.Parent.Left)
                        {
                            Node = Node.Parent;
                            RightRotate(Node);
                        }
                        Node.Parent.NodeColor = RBTreeNodeColor.Black;
                        Node.Parent.Parent.NodeColor = RBTreeNodeColor.Red;
                        LeftRotate(Node.Parent.Parent);
                    }
                }
            }
            //保证根节点为黑色.保证下次while循环可正常结束.
            Root.NodeColor = RBTreeNodeColor.Black;
        }
        /// <summary>
        /// 对一般情况,可以分4种情况考虑:
        /// 1)无孩子,则可直接删除;
        /// 2)只有左孩子:那么只要用左孩子替换当前节点即可;
        /// 3)只有右孩子:那么只要用左孩子替换当前节点即可;
        /// 4)如果有两个孩子:则必须找到当前节点的后继节点y.y要么没孩子,要么只有右孩子。可把把当前节点与y交互信息(key和卫星数据).
        /// 然后删除y(情况1..3).如果Y的颜色为黑色,因为y的删除破坏了红黑树性质,则需要重新整理,如果y是红色的,则删除不会改变
        /// 红黑树的性质.
        /// </summary>
        /// <param name="Node"></param>
        public void RBTreeDelete(RBTreeNode Node)
        {
            //默认theY指向当前节点.
            RBTreeNode theY = Node;
            //如果节点的左右子孩子都不为空,则需找到当前节点的后继节点,theY指向当前节点的后继节点.
            //注意这种情况下,当前节点的后继节点一定是右孩子的最小key节点.而且theY不可能有左孩子。
            if(Node.Right != NullNode && Node.Left != NullNode)
            {
                theY = GetSuccessor(Node);
            }
            RBTreeNode theX = NullNode;
            //theY.Left如果不为空,则theY就是指向Node节点,且没有右孩子.
            //如果theY没有左孩子,则theX指向theY的右孩子,注意theX也可能为空.
            if (theY.Left != NullNode)
            {
                theX = theY.Left;
            }
            else
            {
                theX = theY.Right;
            }
            //开始删除theY.
            theX.Parent = theY.Parent;
            //如果theY.Parent为空,则删除的是根节点,那么theX就变成了根节点。
            if (theY.Parent == NullNode)
            {
                Root = theX;
            }
            else
            {
                if (theY == theY.Parent.Left)
                {
                    theY.Parent.Left = theX;
                }
                else
                {
                    theY.Parent.Right = theX;
                }
            }
            //如果是theY不是指向当前节点,则表明是当前节点有两个孩子的情况,需交互数据.
            if (theY != Node)
            {
                Node.Key = theY.Key;
                //注意这里还序号拷贝卫星数据.
            }
            //如果删除的是黑节点,则必须重新整理(黑度发生变化,破坏了红黑树性质).
            if (theY.NodeColor == RBTreeNodeColor.Black)
            {
                RBTreeDelFixup(theX);
            }
        }
        /// <summary>
        /// 红黑书删除整理.因为删除的节点是黑色,则由此往上需要平衡黑度.
        /// </summary>
        /// <param name="Node"></param>
        public void RBTreeDelFixup(RBTreeNode Node)
        {
            while (Node != Root && Node.NodeColor == RBTreeNodeColor.Black)
            {
                //如果是左孩子
                if (Node == Node.Parent.Left)
                {
                    RBTreeNode theW = Node.Parent.Right;
                    //兄弟节点是红色,父节点必然是黑色,这时可以通过将兄弟节点置为黑色,父节点置为红色,
                    //然后左旋,右孩子保持黑度不变,左孩子黑度还是少1,便于继续处理。.
                    if (theW.NodeColor == RBTreeNodeColor.Red)
                    {
                        theW.NodeColor = RBTreeNodeColor.Black;
                        Node.Parent.NodeColor = RBTreeNodeColor.Red;
                        LeftRotate(Node.Parent);
                        theW = Node.Parent.Right;
                    }
                    //如果兄弟节点的左右孩子都是黑色,则可将兄弟节点置为红色,将需要平衡的节点上移后,还保持要平衡节点
                    //的黑度少1
                    if (theW.Left.NodeColor == RBTreeNodeColor.Black && theW.Right.NodeColor == RBTreeNodeColor.Black)
                    {
                        theW.NodeColor = RBTreeNodeColor.Red;
                        Node = Node.Parent;
                    }
                    else
                    {
                        //如果兄弟节点的孩子有一个是红色的,则可以通过调整就可以达到这种平衡.
                        if (theW.Right.NodeColor == RBTreeNodeColor.Black)
                        {
                            theW.Left.NodeColor = RBTreeNodeColor.Black;
                            theW.NodeColor = RBTreeNodeColor.Red;
                            RightRotate(theW);
                            theW = Node.Parent.Right;
                        }
                        theW.NodeColor = Node.Parent.NodeColor;
                        Node.Parent.NodeColor = RBTreeNodeColor.Black;
                        theW.Right.NodeColor = RBTreeNodeColor.Black;
                        LeftRotate(Node.Parent);
                        Node = Root;
                    }
                }
                else
                {
                    RBTreeNode theW = Node.Parent.Left;
                    //兄弟节点是红色,父节点必然是黑色,这时可以通过将兄弟节点置为黑色,父节点置为红色,
                    //然后右旋,左孩子保持黑度不变,右孩子黑度还是少1,便于继续处理。.
                    if (theW.NodeColor == RBTreeNodeColor.Red)
                    {
                        theW.NodeColor = RBTreeNodeColor.Black;
                        Node.Parent.NodeColor = RBTreeNodeColor.Red;
                        RightRotate(Node.Parent);
                        theW = Node.Parent.Left;
                    }
                    //如果兄弟节点的左右孩子都是黑色,则可将兄弟节点置为红色,将需要平衡的节点上移后,还保持要平衡节点
                    //的黑度少1
                    if (theW.Left.NodeColor == RBTreeNodeColor.Black && theW.Right.NodeColor == RBTreeNodeColor.Black)
                    {
                        theW.NodeColor = RBTreeNodeColor.Red;
                        Node = Node.Parent;
                    }
                    else
                    {
                        //如果兄弟节点的孩子有一个是红色的,则可以通过调整就可以达到这种平衡.
                        if (theW.Left.NodeColor == RBTreeNodeColor.Black)
                        {
                            theW.Left.NodeColor = RBTreeNodeColor.Black;
                            theW.NodeColor = RBTreeNodeColor.Red;
                            LeftRotate(theW);
                            theW = Node.Parent.Left;
                        }
                        theW.NodeColor = Node.Parent.NodeColor;
                        Node.Parent.NodeColor = RBTreeNodeColor.Black;
                        theW.Left.NodeColor = RBTreeNodeColor.Black;
                        RightRotate(Node.Parent);
                        Node = Root;
                    }

                }
                
            }
            Node.NodeColor = RBTreeNodeColor.Black;
        }
        /*所谓二叉树的旋转,其实可以这样理解,当前节点c,和其孩子l,r.看做是滑轮上的三个点,C在滑轮上的支点,l,r分别吊在
         滑轮的两边。左旋的结果就是右边得孩子到了滑轮支点,C向左下滑,右旋则相反,这种旋转,目的就是保持某种平衡。比如右边孩子
         * 如果重了,就会引起不平衡,就需要左旋,当然,因为要保持查找树的性质,左右孩子(l,r)的子节点需要做一定调整.*/
        /// <summary>
        /// 左旋,以当前节点和其右孩子为轴。
        /// </summary>
        /// <param name="Node"></param>
        private void LeftRotate(RBTreeNode Node)
        {
            RBTreeNode theY = Node.Right;
            Node.Right = theY.Left;
            theY.Left.Parent = Node;
            if (Node.Parent == NullNode)
            {
                Root = theY;
            }
            else if (Node == Node.Parent.Left)
            {
                Node.Parent.Left = theY;
            }
            else
            {
                Node.Parent.Right = theY;
            }
            theY.Left = Node;
            Node.Parent = theY;
            
        }
        /// <summary>
        /// 右旋,以当前节点和其左孩子为轴.
        /// </summary>
        /// <param name="Node"></param>
        private void RightRotate(RBTreeNode Node)
        {
            RBTreeNode theY = Node.Left;
            Node.Left = theY.Right;
            theY.Right.Parent = Node;
            if (Node.Parent == NullNode)
            {
                Root = theY;
            }
            else if (Node == Node.Parent.Left)
            {
                Node.Parent.Left = theY;
            }
            else
            {
                Node.Parent.Right = theY;
            }
            theY.Right = Node;
            Node.Parent = theY;
        }
        /// <summary>
        /// 查找树的节点.
        /// </summary>
        /// <param name="Key">关键值.</param>
        /// <returns></returns>
        public RBTreeNode TreeSearch(int Key)
        {
            RBTreeNode theX = Root;
            while (theX != NullNode && theX.Key != Key)
            {
                if (theX.Key < Key)
                {
                    theX = theX.Right;
                }
                else
                {
                    theX = theX.Left;
                }
            }
            return theX;
        }
        /// <summary>
        /// 获取以Node为根节点的子树的最小关键值节点
        /// </summary>
        /// <returns></returns>
        public RBTreeNode GetMinKeyNode(RBTreeNode Node)
        {
            RBTreeNode theX = Node;
            while (theX != NullNode)
            {
                theX = theX.Left;
            }
            return theX;
        }
        /// <summary>
        /// 获取以指定节点为根的子树的最大关键值节点
        /// </summary>
        /// <returns></returns>
        public RBTreeNode GetMaxKeyNode(RBTreeNode Node)
        {
            RBTreeNode theX = Node;
            while (theX != NullNode)
            {
                theX = theX.Right;
            }
            return theX;
        }
        /// <summary>
        /// 寻找指定节点的后继节点.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public RBTreeNode GetSuccessor(RBTreeNode Node)
        {
            //如果当前节点右孩子不为空,则后续节点显然是右孩子子树的最小节点。
            if (Node.Right != NullNode)
            {
                return GetMinKeyNode(Node.Right);
            }
            RBTreeNode theF = Node.Parent;
            //如果当前节点的右孩子为空,则从其父节点开始判断,如果当前节点是其父节点的左孩子,则后续节点就是父节点.
            //如果是右孩子,则继续向上寻找,直到为空或者当前节点是其父节点的左孩子为止.
            while (theF != NullNode && Node != theF.Right)
            {
                Node = theF;
                theF = theF.Parent;
            }
            return theF;
        }
        /// <summary>
        /// 寻找指定节点的继节点.
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public RBTreeNode GetPredecessor(RBTreeNode Node)
        {
            //如果当前节点左孩子不为空,则后续节点显然是左孩子子树的最大节点。
            if (Node.Left != NullNode)
            {
                return GetMaxKeyNode(Node.Left);
            }
            RBTreeNode theF = Node.Parent;
            //如果当前节点的左孩子为空,则从其父节点开始判断,如果当前节点是其父节点的右孩子,则后续节点就是父节点.
            //如果是左孩子,则继续向上寻找,直到为空或者当前节点是其父节点的右孩子为止.
            while (theF != NullNode && Node != theF.Left)
            {
                Node = theF;
                theF = theF.Parent;
            }
            return theF;
        }
    }
    
}


参考算法导论.


更正:

 /// <summary>
        /// 左旋,以当前节点和其右孩子为轴。
        /// </summary>
        /// <param name="Node"></param>
        private void LeftRotate(RBTreeNode Node)
        {
            RBTreeNode theY = Node.Right;
            Node.Right = theY.Left;
            theY.Left.Parent = Node;
            
            theY.Parent = Node.Parent;

            if (Node.Parent == NullNode)
            {
                Root = theY;
            }
            else if (Node == Node.Parent.Left)
            {
                Node.Parent.Left = theY;
            }
            else
            {
                Node.Parent.Right = theY;
            }
            theY.Left = Node;
            Node.Parent = theY;

        }
        /// <summary>
        /// 右旋,以当前节点和其左孩子为轴.
        /// </summary>
        /// <param name="Node"></param>
        private void RightRotate(RBTreeNode Node)
        {
            RBTreeNode theY = Node.Left;
            Node.Left = theY.Right;
            theY.Right.Parent = Node;
            
            theY.Parent = Node.Parent;
            if (Node.Parent == NullNode)
            {
                Root = theY;
            }
            else if (Node == Node.Parent.Left)
            {
                Node.Parent.Left = theY;
            }
            else
            {
                Node.Parent.Right = theY;
            }
            theY.Right = Node;
            Node.Parent = theY;
        }
 /// <summary>
        /// 插入节点,这里假设了所有的节点key不相同.
        /// </summary>
        /// <param name="Node"></param>
        public void InsertNode(RBTreeNode Node)
        {
            ///寻找插入节点的插入点(父节点)theY.TheX是循环中间变量.
            RBTreeNode theY = NullNode;
            RBTreeNode theX = Root;
            //注意,如果不为空,则找到的插入节点一定是最底层内节点,仅有空字节点(哨兵节点).
            //这也是红黑树不是高度平衡树的一个重要原因.但这样简化了插入,不用判断补缺.
            while (theX != NullNode)
            {
                theY = theX;
                if (Node.Key > theX.Key)
                {
                    theX = theX.Right;
                }
                else
                {
                    theX = theX.Left;
                }
            }
            //将插入节点的父节点指向theY.
            Node.Parent = theY;
            //如果theY为空,则原来是空树,则新插入的节点是根节点.
            if (theY == NullNode)
            {
                Root = Node;
            }
            else
            {
                //如果有根节点,与theY的Key比较,大于则作为右子节点,小于则
                //作为左节点.
                if (Node.Key > theY.Key)
                {
                    theY.Right = Node; //此处原来写错Node.Parent=theY.Right;
                }
                else
                {
                    theY.Left = Node; //此处原文写错Node.Parent=theY.Left;
                }
            }
            //开始插入的节点都在非空叶子节点上,将空节点作为其两个子节点.
            Node.Right = NullNode;
            Node.Left = NullNode;
            //颜色置为红,然后整理.
            Node.NodeColor = RBTreeNodeColor.Red;
            RBInsertFixup(Node);
        }

更正后插入没问题,其它地方没有检验,如不行可参考算法导论完成即可。

 

深度学习框架对比:AI开发如何选择 你是否遇到过这样的困惑:想做一个图像分类模型,朋友推荐PyTorch;公司要部署智能客服,同事说用TensorFlow;想快速验证想法,学长又提到Keras……深度学习框架种类繁多,功能重叠却各有侧重。本文将覆盖主流框架(PyTorch/TensorFlow/Keras/JAX/MXNet等),从开发者真实需求出发,总结选择框架的核心维度。本文将按照“认识框架→对比特性→实战选择”的逻辑展开:先通过生活比喻理解各框架特点,再用代码对比核心功能,最后结合真实场景给出选择建议。动态计算图。 阅读详情

相关推荐

CC2340R5-OAD升级实战:从配置到调试的全流程解析

本文详细解析CC2340R5芯片的OAD(空中升级)全流程,涵盖环境配置、MCU-BOOT、OAD-BL和OAD-APP程序开发,以及内存布局和调试技巧。通过实战案例展示如何实现蓝牙设备的远程固件升级,提升开发效率和产品可维护性。

silver的专栏 1063

带你手写红黑树——500行代码

手写一个红黑树 既然红黑树如此的不友好,那么我就来手写一个红黑树,来细致地探究一下该如何实现一个属于自己的红黑树,这样自己也好有个底_。 500+行代码实现一个红黑树: 树的设计 public class RBTree<Key extends Comparable<Key>, Value> { /****************颜色常量***************************/ private static final boolean RED = tr

LengDanRan 5096

Camera metadata

Camera metadata

weixin_42136255的博客 2529

HashMap底层红黑树原理(超详细图解)+手写红黑树代码

在看完了小刘老师和黑马的源码视频之后,我整理了一篇HashMap的底层源码文章,学海无涯,这几天看了对红黑树的讲解,故将其整理出来 HashMap底层源码解析上 HashMap底层源码解析下 视频链接 小刘老师讲源码 传智播客-黑马程序员 文章目录红黑树什么是树 红黑树 什么是树 树(tree)是一种抽象数据类型(ADT),用来模拟具有树状结构性质的数据集合,它是由n(n>0)个有限节点通过连接它们的边组成一个具有层次关系的集合。把它叫做“树”是因为他看起来像一颗倒挂的树,也就是说它是根朝上,而叶向

wenwenaier的博客 2万+

全球、中国各省市县等行政区划(含十段线)shape及geosjon数据免费下载

免费下载全球、中国各省市县等行政区划(含十段线)shape及geosjon数据

mhf403445651的博客 3460

Canoe CAPL TCP通信避坑指南:从OnTcpConnect回调不触发到Socket句柄管理

本文详细解析了Canoe CAPL中TCP通信的常见问题与解决方案,包括OnTcpConnect回调不触发的三大原因、Socket句柄管理的内存泄漏风险、数据发送截断规则等。通过实战案例和代码示例,帮助开发者规避TCP通信中的典型陷阱,提升车载网络测试的稳定性和可靠性。

weixin_26976635的博客 358

手写红黑树都不会,张口就要1万8——清华程序员面试就这样被HR嘲讽了

写在前面:2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上,内容详细,图文并茂,有需要学习的朋友可以Star一下! GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master 一名互联网外企的HR在互联网匿名社区描述自己面试清华学子的经历,称自己面试的一个毕业一年的清华的小孩,让写个红黑树的添加删除算法,支吾了半个小时,写的还不对,张嘴还要18000,都膨胀成这样了。 据了解,红黑树是计算机专业的专有名词,与

qwe123147369的博客 4529

避坑指南:Dify+Docker+Ollama离线部署实战与疑难解析

本文详细解析了在国产化系统(如银河麒麟V10)内网环境中,如何从零开始离线部署Dify、Docker与Ollama的全栈AI应用开发平台。文章重点拆解了Docker安装中的“没有Release文件”和“GPG密钥错误”等典型报错解决方案,并提供了Ollama离线模型导入与Dify连接配置的完整实战指南,旨在帮助开发者高效完成本地部署,避开常见陷阱。

dd012的博客 465

手写红黑树【数据结构】

手写红黑树【数据结构】

小心星的博客 1378

R语言实战:Scheirer–Ray–Hare检验在非正态重复测量数据分析中的应用

本文详细介绍了当重复测量数据不满足正态分布假设时,如何利用R语言中的Scheirer–Ray–Hare检验进行数据分析。该检验作为非参数方法,无需数据服从正态分布或方差齐性,适用于分析组间差异、时间效应及其交互作用。文章通过实战案例,从环境搭建、数据准备、检验执行到结果解读与可视化,提供了完整的操作指南,帮助研究者有效处理心理学、医学等领域的复杂实验数据。

salt9的博客 780

Modbus通信从入门到精通_2_Modbus TCP通信详解及仿真(搭建ModbusTCP仿真环境:创建虚拟PLC并进行ModbusTCP通讯;寄存器与PLC中映射关系;适合理解如何编写上位机)

LocalPort”是PLC的端口,最终的设置如下图所示:(相关的设置都可以查看帮助文档)P#DB1.DBX0.0 BYTE28是以指针形式表示的DB1的DBX0.0开始(在使用的西门子Modbus tcp的程序块中设置的“MB_HOLD_REG”输出寄存器),其有28个字节(28个字节对应14个寄存器),4001是第一个寄存器,往后数14个即可。在上面的基础上,增加一个“DB1”的“组对象”,同时将“MW0”的组对象禁止(双击组对象,“Active”取消勾选),启动之后发现无法连接。

分享学习成长历程,Winter is coming! 1万+

红黑树(一条龙解析)

二叉搜索树 二叉搜索树要求: ​ 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; ​ 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; ​ 它的左、右子树也分别为二叉排序树。(小 中 大) 二叉搜索树-删除节点: 删除节点是二叉搜索树中最复杂的操作,删除的节点有三种情况,前两种比较简单,但是第三种却很复杂。 1、该节点是叶节点(没有子节点) 2、该节点有一个子节点 3、该节点有两个子节点

lxsxkf的博客 397

道路场景分割:车道线、可行驶区域与路沿检测

道路场景分割:车道线、可行驶区域与路沿检测​ ,人工智能,计算机视觉,大模型,AI,文章围绕道路场景分割展开,涵盖车道线、可行驶区域与路沿检测。介绍了基本概念、重要性,各部分检测的类型、方法、难点及解决思路,还涉及技术融合、数据集、评价指标、发展趋势、应用案例、代码示例、不同天气处理、实际问题与方案、实现流程、相关技术工具、教育研究应用、产业前景、伦理安全问题及学习资源等,全面阐述了道路场景分割的多方面内容,为相关学习和研究提供了丰富信息。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 22万+

红黑树算法笔记(一)

红黑树基本概念及操作笔记以及简单性能对比实验。

Jerry的博客 1621

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

算法笔记 - 红黑树

红黑树 红黑树也是一种自平衡的二叉搜索树,以前也叫做平衡二叉树 红黑树必须满足五条性质: 节点是 RED 或者 BLACK 根节点是 BLACK 叶子节点(外部节点、空结点)都是 BLACK RED 节点的子节点都是 BLACK,RED节点的 parent 都是 BLACK,从根节点到叶子节点的所有路径上不能有 2 个连续的 RED 节点 从任一节点到叶子节点的所有路劲都包含相同数目的 BLACK 节点 错误实例 红黑树的等价变换 ...

-happy 的博客 196

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

[算法导论笔记]--红黑树

一.什么是红黑树 红黑树是一棵二叉搜索树,其在每个结点上增加了一个存储位来表示颜色,可以是红(red)或者黑(black)。通过任何一条从"根到叶子的简单路径"上的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍,因而是近似于平衡的。红黑树是一种平衡二叉树。 红黑树的基本性质 (1)每个结点要么是红色的,要么是黑色的(废话..) (2)根结点是黑色的 (3)叶子结点是黑色的(也可...

Alfeim的博客 400

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

算法笔记-红黑树1

上一篇总结中二叉查找树支持快速查找,删除以及插入操作,时间复杂度与树的高度成正比,理想情况下是 O(logn)。 但是在频繁插入删除的情况下,树的高度可能就大于 log2|n。极端情况下,树可以退化成链表这种结构,那么相应的操作效率也就下降了。 针对这种情况,为了保持二叉查找树的执行效率高效,出现了平衡二叉查找树,其中最广为人知的就是红黑树。 什么是平衡二叉查找树 二叉树中任意节点的左右子树的高度...

java程序员笔记 236

红黑树算法探索笔记

最近花了些时间重拾数据结构的基础知识,先尝试了红黑树,花了大半个月的时间研究其原理和实现,下面是学习到的知识和一些笔记的分享。望各位多多指教。本次代码的实现请点击:红黑树实现代码 – gist红黑树基础知识定义红黑树是带有 color 属性的二叉搜索树,color 的值为红色或黑色,因此叫做红黑树。对红黑树的每个结点的结构体定义如下:struct RBNode { int color; ...

qq_37101453的博客 258

【算法笔记】红黑树插入操作

红黑树是一种NIL。

fans2306的博客 448

算法笔记:二叉树,红黑树

题目一:二叉树的前中后序遍历: 以上是节点的访问顺序:每个节点回来到三次 1.前序遍历:节点第一次出现的时候打印;前-左-右 2.中序遍历:节点第二次出现的时候打印;左-前-右 3.后序遍历:节点第三次出现的时候打印;左-右-前 代码:(递归方法+非递归方法): package zuoshen4; import java.util.Stack; public class Code_01_PreInPosTraversal { public static class Node{

weixin_44021180的博客 453

算法学习笔记15:红黑树

眼前的黑不是黑,你说的红是什么红,本篇博客带你初探红黑树的奥秘。

JRcoder 391

《ads》课程《算法导论》红黑树笔记

算法导论兼课程学习笔记,红黑树

weixin_73891756的博客 1272

《算法4》红黑树原理实现---笔记

前面讲了AVL平衡树的实现https://blog.youkuaiyun.com/weixin_43696529/article/details/104701374,但由于AVL是高度平衡的树(高度差小于等于1),而红黑树是根据颜色来不严格的实现平衡,因此在插入和删除节点时,红黑树的调整次数较少,尤其是在大量数据面前时,红黑树的效率会更高。 一、定义介绍 首先我们需要知道什么是2-节点,什么是3-节点。 2-...

一颗小陨石的博客 740

算法导论ch13红黑树笔记与相应数据结构算法c++实现(上)

一起寿司红黑树

Yunhandu的博客 1267

算法导论笔记之红黑树

13、红黑树 13.1红黑树的性质 红黑树是一颗二叉搜索树,通过对任何一条从根到叶子的简单路径上各个节点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出两倍, 因而是近似平衡的。树中的节点包括5个属性:color、key、left、right、p。 一颗红黑树满足下面5条性质: 1、每个节点或是红色的、或是黑色的。 2、根节点是黑色的 3、每个叶子节点(NIL)是黑色的 ...

weixin_30384031的博客 212

Java数据结构与算法笔记——红黑树详解

文章目录二叉搜索树缺点红黑树红黑树简介红黑树规则插入节点红黑树自我修正改变节点颜色右旋左旋红黑树纠正算法对于情况1对于情况2对于情况3红黑树性能分析 二叉搜索树缺点 二叉搜索树对于某个节点而言,其左子树的节点关键值都小于该节点关键值,右子树的所有节点关键值都大于该节点关键值。二叉搜索树作为一种数据结构,其查找、插入和删除操作的时间复杂度都为O(logn),底数为2。 但是我们说这个时间复杂度是在平衡的二叉搜索树上体现的,也就是如果插入的数据是随机的,则效率很高,但是如果插入的数据是有序的,比如从小到大的顺序

Mr_Wanderer的博客 638
上一篇: 算法笔记(有根树遍历)
下一篇: 算法笔记(问题分解,分治与动态规划)
广州接入
广州接入 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄24年 2224粉丝 731原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值