面试-动态查找-笔记

动态查找树

静态查找结构:顺序查找、折半查找

动态查找结构:二叉查找树、平衡二叉树、红黑树、B/B+树

 

当所有的静态查找结构添加和删除一个数据的时候,整个结构都要重建,需要动态查找结构。

 

1.二叉查找树(BinarySearch Tree - BST)

引入:解决静态查找时 添加和删除 的低效问题

定义:

1.  若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值

2.  若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值

3.  它的左、右子树也分别为二叉查找树

中序遍历这两棵树发现一个有序的数据序列: 【1 2  3  4  5  6  7  8 】

代价:

1.  动态添加任何一个数据,都会加在原树结构的叶子节点上,而不会重新建树。

2.  如果二叉查找树中需要删除的结点左、右子树都存在,则删除的时候需要改变一些子树结构,但所需要付出的代价很小。

       效率:

      上图中的a,b,c我们在a图中查找8需要比较5次数据,而在B图中只需要比较3次。更为严重的是:如果按有序序列[1 2 3 4 5 6 7 8]建立一颗二叉查找树,整棵树就退化成了一个线性结构(如c输入图:单支树),此时查找8需要比较8次数据,和顺序查找没有什么不同。

       因此, 最坏情况下,构成的二叉排序树蜕变为单支树,树的深度为n,其查找时间复杂度与顺序查找一样O(N)。最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log2(N)成正比 (O(log2(n)))。

问题:

       同样一组数据集合,不同的添加顺序会导致查找树的结构完全不一样,直接影响了查找效率。平衡二叉树可以有效解决这个问题。

 


2.   平衡二叉树(AVL)

引入:

       在二叉查找树中,不同结构其查找效率差别很大,因此需要最大限度的减少树的深度,基于此,平衡二叉树AVL提出。

定义:

1.  二叉查找树的属性

2.  它 的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值(平衡因子 ) 不超过1。

3.       当在二叉排序树中插入一个节点时,首先检查是否因插入而破坏了平衡,若 破坏,则找出其中的最小不平衡二叉树,在保持二叉排序树特性的情况下,调整最小不平衡子树中节点之间的关系,以达到新的平衡。所谓最小不平衡子树 指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。 

算法(插入):

             保持平衡的 方法 – 旋转

                   平衡因子:该节点的左子树 — 右子树,如果其绝对值>1,则出现不平衡

                  四种类型:A为重节点(平衡因子为1)

(1) LL 型:
  新结点 X 插在 A 的左孩子的左子树里。调整方法见图 8.5(a) 。图中以 B 为轴心,将 A 结点从 B 的右上方转到 B 的右下侧,使 A 成为 B 的右孩子。


          图8.5 平衡调整的4种基本类型(结点旁的数字是平衡因子)

(2)RR 型:
  新结点 X 插在 A 的右孩子的右子树里。调整方法见图 8.5(b) 。图中以 B 为轴心,将 A 结点从 B 的左上方转到 B 的左下侧,使 A 成为 B 的左孩子。
(3)LR 型:
  新结点 X 插在 A 的左孩子的右子树里。调整方法见图 8.5(c) 。分为两步进行:第一步以 X 为轴心,将 B 从 X 的左上方转到 X 的左下侧,使 B 成为 X 的左孩子, X 成为 A 的左孩子。第二步跟 LL 型一样处理 ( 应以 X 为轴心 ) 。 
(4)RL 型:
  新结点 X 插在 A 的右孩子的左子树里。调整方法见图 8.5(d) 。分为两步进行:第一步以 X 为轴心,将 B 从 X 的右上方转到 X 的右下侧,使 B 成为 X 的右孩子, X 成为 A 的右孩子。第二步跟 RR 型一样处理 ( 应以 X 为轴心 ) 。

例子:16 3 7 11 9 26 18 14 15 

分析:

       平衡二叉树的优势在于不会出现普通二叉查找树的最差情况。其查找的时间复杂度为O(logN)。

问题:N层平衡二叉树至少多少个结点?

解答:假设F(N)表示N层平衡二叉树的结点个数,则F[1]=1,F[2]=2。而F(N)=F(N-2)+F(N-1)+1。为什么呢?我们可以这样考虑,假设现在又一个(N-2)层和(N-1)层的最少结点平衡二叉树。要构造一棵N层的平衡二叉树,则只需加入一个根节点,其左右子树分别(N-2)层和(N-1)层的树即可 。由于两个子树都是最少结点的,所有N层的也是最少结点的。

缺陷:

1.     为了保证高度平衡,动态插入和删除的代价也随之增加。《红黑树》 是解决这种问题的更加高效的查找结构。

2.     二叉查找树结构的查找代价都与树高是紧密相关的,能否通过减少树高来进一步降低查找代价呢。可以通过多路查找树的结构来做到这一点,在后面专题中我们将通过《多路查找树/B-树/B+树 》来介绍。

3.     在大数据量查找环境下(比如说系统磁盘里的文件目录,数据库中的记录查询 等),所有的二叉查找树结构(BST、AVL、RBT)都不合适。如此大规模的数据量(几G数据),全部组织成平衡二叉树放在内存中是不可能做到的。那么把这棵树放在磁盘中吧。问题就来了:假如构造的平衡二叉树深度有1W层。那么从根节点出发到叶子节点很可能就需要1W次的硬盘IO读写。大家都知道,硬盘的机械部件读写数据的速度远远赶不上纯电子媒体的内存。 查找效率在IO读写过程中将会付出巨大的代价。在大规模数据查询这样一个实际应用背景下,平衡二叉树的效率就很成问题了。对这一问题的解决:我们也会在《多路查找树/B-树/B+树 》 将详细分析。


 

3. 红黑树

         引入:

        在平衡二叉树中,插入时频繁的插入和删除代价也随之增加,红黑树就是解决这个问题的。

性质:

1.     二叉排序树的性质;

2.     每一个结点要么是红色,要么是黑色;

3.     根结点是黑色的;

4.     所有叶子结点都是黑色的(实际上都是Null指针,下图用NIL表示)。叶子结点不包含任何关键字信息,所有查询关键字都在非终结点上;

5.     每个红色结点的两个子节点必须是黑色的。换句话说:从每个叶子到根的所有路径上不能有两个连续的红色结点;

6.     从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

概念:

黑深度 ——从某个结点x出发(不包括结点x本身)到叶结点(包括叶子结点)的路径上的黑结点个数,称为该结点x的黑深度,记为bd(x),根结点的黑深度就是该红黑树的黑深度。叶子结点的黑深度为0。比如:上图bd(13)=2,bd(8)=2,bd(1)=1

内部结点 —— 红黑树的非终结点

外部节点 —— 红黑树的叶子结点

定理:

       从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。

    红黑树的树高(h)不大于两倍的红黑树的黑深度(bd),即h<=2bd

一棵拥有n个内部结点(不包括叶子结点)的红黑树的树高h<=2log(n+1)

插入:http://dongxicheng.org/structure/red-black-tree/

         (1) 查找要插入的位置,时间复杂度为:O(N)

(2)将新节点的color赋为红色

(3)自下而上重新调整该树为红黑树

删除:

         (1) 查找要删除位置,时间复杂度为:O(N)

(2)用删除节点后继或者节点替换该节点(只进行数据替换即可,不必调整指针,后继节点是中序遍历中紧挨着该节点的节点,即:右孩子的最左孩子节点)

(3)如果删除节点的替换节点为黑色,则需重新调整该树为红黑树

4. B树

       引入:

二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),红黑树(Red-Black Tree ) 是典型的二叉查找树结构,其查找的时间复杂度O(log2N)与树的深度相关,那么降低树的深度自然会提高查找效率。大量数据存储中,实现查询这样一个实际背景下,平衡二叉树由于树深度过大而造成磁盘IO读写过于频繁,进而导致效率低下。那么如何减少树的深度(当然不能减少查询数据量),一个基本的想法就是:

1.      每个节点存储多个元素 (但元素数量不能无限多,否则查找就退化成了节点内部的线性查找了)。

2.      摒弃二叉树结构,采用多叉树 (由于节点内元素数量不能无限多,自然子树的数量也就不会无限多了)。

这样我们就提出来了一个新的查找树结构 ——多路查找树。 根据AVL给我们的启发,一颗平衡多路查找树(B~树)自然可以使得数据的查找效率保证在O(logN)这样的对数级别上。

 

4.1 【2-4树】

   (2,4)树是一棵典型的平衡多路查找树。性质如下:

1.   大小性质:每个结点最多4个子结点。

2.   深度性质:所有外部结点的深度相同。

(2,4)其实是一棵迷你型的B树,其主要应用并不是为了将大数据量存储在外存上,而是通过减少树高来降低二叉查找树的查找代价。

4.2 【B~树】

B~树,又叫平衡多路查找树。一棵m阶的B~树 (m叉树)的特性如下:

1)    树中每个结点至多有m个孩子;

2)    除根结点和叶子结点外,其它每个结点至少有[m/2]个孩子;

3)    若根结点不是叶子结点,则至少有2个孩子;

4)    所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息(可以看做是外部接点或查询失败的接点,实际上这些结点不存在,指向这些结点的指针都为null);

5)    每个非终端结点中包含有n个关键字信息: (n,A0,K1,A1,K2,A2,......,Kn,An)。其中,

a)     Ki (i=1...n)为关键字,且关键字按顺序排序Ki < K(i-1)。

b)    Ai为指向子树根的接点,且指针A(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。

c)     关键字的个数n必须满足:  [m/2]-1 <= n <= m-1

 

若n≥1,m≥3,则对任意一棵具有n个关键字的m阶B-树,其树高至少为:

Logm(n+1);

其树高h至多为:

logt((n+1)/2)+1。

这里t是每个(除根外)内部结点的最小度数,即

        

一颗m阶B树,每个非根节点的关键字书目最少为:m/2上届-1,最多为m-1;其子树的子树最少为:m/2 的上届,最多为:m

 

例如:下面就是一棵3阶B~树

(为了简单,这里用少量数据构造一棵2-4树的形式,其实实际应用中的B树结点中关键字很多的)

 

4.3 【B+树】

B+树:是应文件系统所需而产生的一种B~树的变形树。

 一棵m阶的B+树和m阶的B-树的差异在于:

1)    有n棵子树的结点中含有n个关键字;  (B~树是n棵子树有n+1个关键字)

2)    所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (B~树的叶子节点并没有包括全部需要查找的信息)

3)    所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (B~树的非终节点也包含需要查找的有效信息)

 

例如:下面就是一棵3阶B+树。我们可以和B~树做一个明显的对比。

               B+树的叶子结点包含了所有待查询关键字,而非终节点只是作为叶子结点中最大(最小)关键字的索引。因此B+树的非终结点没有文件内容所在物理存储的地址,而B~树所有结点均有文件内容所在的磁盘物理地址(B~树结构图中结点内部的小红方块)。 这个特点是B+树的一个重要优势所在

B+树的优势所在

   为什么说B+树比B~树更适合实际应用中操作系统的文件索引和数据库索引?

1、B+树的磁盘读写代价更低

我们都知道磁盘时可以块存储的,也就是同一个磁道上同一盘块中的所有数据都可以一次全部读取(详见《 外部存储器—磁盘 》 )。而B+树的内部结点并没有指向关键字具体信息的指针(比如文件内容的具体地址 , 比如说不包含B~树结点中的FileHardAddress[filenum]部分) 。因此其内部结点相对B~树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。这样,一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B~树(一个结点最多8个关键字)的内部结点需要2个盘快。而B+树内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B~树就比B+数多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。

2、B+树的查询效率更加稳定

由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

 

 

5. 动态查找树比较

介绍的动态查找树主要有: 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)。这四种树都具备下面几个优势:

1.     都是动态结构。在删除,插入操作的时候,都不需要彻底重建原始的索引树。最多就是执行一定量的旋转,变色操作来有限的改变树的形态。而这些操作所付出的代价都远远小于重建一棵树。这一优势在《查找结构专题(1):静态查找结构概论 》中讲到过。

2.     查找的时间复杂度大体维持在O(log(N))数量级上。可能有些结构在最差的情况下效率将会下降很快,比如BST。这个会在下面的对比中详细阐述。

下面我们开始概括性描述这四种树,并相互比较一下优劣。

二叉查找树  (Binary Search Tree)  

详细见《查找结构专题(2):二叉查找树[BST] 》

      很显然,二叉查找树的发现完全是因为静态查找结构在动态插入,删除结点所表现出来的无能为力(需要付出极大的代价)。

 

   BST 的操作代价分析:

1)     查找代价: 任何一个数据的查找过程都需要从根结点出发,沿某一个路径朝叶子结点前进。因此查找中数据比较次数与树的形态密切相关。

当树中每个结点左右子树高度大致相同时,树高为logN。则平均查找长度与logN成正比,查找的平均时间复杂度在O(logN)数量级上。

当先后插入的关键字有序时,BST退化成单支树结构。此时树高n。平均查找长度为(n+1)/2,查找的平均时间复杂度在O(N)数量级上。

2)     插入代价: 新结点插入到树的叶子上,完全不需要改变树中原有结点的组织结构。插入一个结点的代价与查找一个不存在的数据的代价完全相同。

3)     删除代价: 当删除一个结点P,首先需要定位到这个结点P,这个过程需要一个查找的代价。然后稍微改变一下树的形态。如果被删除结点的左、右子树只有一个存在,则改变形态的代价仅为O(1)。如果被删除结点的左、右子树均存在,只需要将当P的左孩子的右孩子的右孩子的...的右叶子结点与P互换,在改变一些左右子树即可。因此删除操作的时间复杂度最大不会超过O(logN)。

 

    BST效率总结 :  查找最好时间复杂度O(logN),最坏时间复杂度O(N)。

                            插入删除操作算法简单,时间复杂度与查找差不多

 

平衡二叉查找树 ( Balanced Binary Search Tree ) 

详细见《查找结构专题(3):平衡二叉查找树[AVL] 

      二叉查找树在最差情况下竟然和顺序查找效率相当,这是无法仍受的。事实也证明,当存储数据足够大的时候,树的结构对某些关键字的查找效率影响很大。当然,造成这种情况的主要原因就是BST不够平衡(左右子树高度差太大)。

      既然如此,那么我们就需要通过一定的算法,将不平衡树改变成平衡树。因此,AVL树就诞生了。

 

    AVL 的操作代价分析:

    (1) 查找代价: AVL是严格平衡的BST(平衡因子不超过1)。那么查找过程与BST一样,只是AVL不会出现最差情况的BST(单支树)。因此查找效率最好,最坏情况都是O(logN)数量级的。

 

    (2) 插入代价: AVL必须要保证严格平衡(|bf|<=1),那么每一次插入数据使得AVL中某些结点的平衡因子超过1就必须进行旋转操作。事实上,AVL的每一次插入结点操作最多只需要旋转1次(单旋转或双旋转)。因此,总体上插入操作的代价仍然在O(logN)级别上(插入结点需要首先查找插入的位置)。

 

    (3) 删除代价:AVL删除结点的算法可以参见BST的删除结点,但是删除之后必须检查从删除结点开始到根结点路径上的所有结点的平衡因子。因此删除的代价稍微要大一些。每一次删除操作最多需要O(logN)次旋转。因此,删除操作的时间复杂度为O(logN)+O(logN)=O(2logN)

 

    AVL 效率总结 :  查找的时间复杂度维持在O(logN),不会出现最差情况

                           AVL树在执行每个插入操作时最多需要1次旋转,其时间复杂度在O(logN)左右。

                           AVL树在执行删除时代价稍大,执行每个删除操作的时间复杂度需要O(2logN)。

 

 

 

 

3. 红黑树(Red-Black Tree ) 详细见《查找结构专题(4):红黑树[RBT] 》

 

    二叉平衡树的严格平衡策略以牺牲建立查找结构(插入,删除操作)的代价,换来了稳定的O(logN) 的查找时间复杂度。但是这样做是否值得呢?

 

    能不能找一种折中策略,即不牺牲太大的建立查找结构的代价,也能保证稳定高效的查找效率呢? 答案就是:红黑树。

 

    RBT 的操作代价分析:

     (1) 查找代价:由于红黑树的性质(最长路径长度不超过最短路径长度的2倍),可以说明红黑树虽然不像AVL一样是严格平衡的,但平衡性能还是要比BST要好。其查找代价基本维持在O(logN)左右,但在最差情况下(最长路径是最短路径的2倍少1),比AVL要略逊色一点。

 

    (2) 插入代价:RBT插入结点时,需要旋转操作和变色操作。但由于只需要保证RBT基本平衡就可以了。因此插入结点最多只需要2次旋转,这一点和AVL的插入操作一样。虽然变色操作需要O(logN),但是变色操作十分简单,代价很小。

 

    (3) 删除代价:RBT的删除操作代价要比AVL要好的多,删除一个结点最多只需要3次旋转操作。

 

    RBT 效率总结 : 查找 效率最好情况下时间复杂度为O(logN),但在最坏情况下比AVL要差一些,但也远远好于BST。

                          插入和删除操作改变树的平衡性的概率要远远小于AVL(RBT不是高度平衡的)。因此需要的旋转操作的可能性要小,而且一旦需要旋转,插入一个结点最多只需要旋转2次,删除最多只需要旋转3次(小于AVL的删除操作所需要的旋转次数)。虽然变色操作的时间复杂度在O(logN),但是实际上,这种操作由于简单所需要的代价很小。

 

 

 

 

4. B~树/B+树(B-Tree ) 详细见《查找结构专题(5):B~树/B+树 》

 

     对于在内存中的查找结构而言,红黑树的效率已经非常好了(实际上很多实际应用还对RBT进行了优化)。但是如果是数据量非常大的查找呢?将这些数据全部放入内存组织成RBT结构显然是不实际的。实际上,像OS中的文件目录存储,数据库中的文件索引结构的存储.... 都不可能在内存中建立查找结构。必须在磁盘中建立好这个结构。那么在这个背景下,RBT还是一种好的选择吗?

 

     在磁盘中组织查找结构,从任何一个结点指向其他结点都有可能读取一次磁盘数据,再将数据写入内存进行比较。大家都知道,频繁的磁盘IO操作,效率是很低下的(机械运动比电子运动要慢不知道多少)。显而易见,所有的二叉树的查找结构在磁盘中都是低效的。因此,B树很好的解决了这一个问题。

 

    B-Tree的操作代价分析:

    (1) 查找代价: B-Tree作为一个平衡多路查找树(m-叉)。B树的查找分成两种:一种是从一个结点查找另一结点的地址的时候,需要定位磁盘地址(查找地址),查找代价极高。另一种是将结点中的有序关键字序列放入内存,进行优化查找(可以用折半),相比查找代价极低。而B树的高度很小,因此在这一背景下,B树比任何二叉结构查找树的效率都要高很多。而且B+树作为B树的变种,其查找效率更高。

 

    (2)插入代价: B-Tree的插入会发生结点的分裂操作。当插入操作引起了s个节点的分裂时,磁盘访问的次数为h(读取搜索路径上的节点)+2s(回写两个分裂出的新节点)+1(回写新的根节点或插入后没有导致分裂的节点)。因此,所需要的磁盘访问次数是h+2s+1,最多可达到3h+1。因此插入的代价是很大的。

 

    (3)删除代价:B-Tree的删除会发生结点合并操作。最坏情况下磁盘访问次数是3h=(找到包含被删除元素需要h次
读访问)+(获取第2至h层的最相邻兄弟需要h-1次读访问)+(在第3至h层的合并需要h-2次写
访问)+(对修改过的根节点和第2层的两个节点进行3次写访问)

 

   B-Tree效率总结: 由于考虑磁盘储存结构,B树的查找、删除、插入的代价都远远要小于任何二叉结构树(读写磁盘次数的降低)。

 

 

 

 

动态查找树结构的对比:

 

(1) 平衡二叉树和红黑树  [AVL  PK  RBT]

 

      AVL 和RBT 都是二叉查找树的优化。其性能要远远好于二叉查找树。他们之间都有自己的优势,其应用上也有不同。

 

      结构对比: AVL的结构高度平衡,RBT的结构基本平衡。平衡度AVL > RBT.

 

      查找对比: AVL 查找时间复杂度最好,最坏情况都是O(logN)。

                     RBT 查找时间复杂度最好为O(logN),最坏情况下比AVL略差。

 

      插入删除对比:  1. AVL的插入和删除结点很容易造成树结构的不平衡,而RBT的平衡度要求较低。因此在大量数据插入的情况下,RBT需要通过旋转变色操作来重新达到平衡的频度要小于AVL。

                            2. 如果需要平衡处理时,RBT比AVL多一种变色操作,而且变色的时间复杂度在O(logN)数量级上。但是由于操作简单,所以在实践中这种变色仍然是非常快速的。

                            3. 当插入一个结点都引起了树的不平衡,AVL和RBT都最多需要2次旋转操作。但删除一个结点引起不平衡后,AVL最多需要logN 次旋转操作,而RBT最多只需要3次。因此两者插入一个结点的代价差不多,但删除一个结点的代价RBT要低一些。

                            4. AVL和RBT的插入删除代价主要还是消耗在查找待操作的结点上。因此时间复杂度基本上都是与O(logN) 成正比的。

 

        总体评价:大量数据实践证明,RBT的总体统计性能要好于平衡二叉树。

 

 

(2) B~树和B+树    [ B~Tree   PK  B+Tree]

 

      B+树是B~树的一种变体,在磁盘查找结构中,B+树更适合文件系统的磁盘存储结构。

 

      结构对比: B~树是平衡多路查找树,所有结点中都包含了待查关键字的有效信息(比如文件磁盘指针)。每个结点若有n个关键字,则有n+1个指向其他结点的指针。

                    B+树严格意义上说已经不是树,它的叶子结点之间也有指针链接。B+树的非终结点中并不含有关键字的信息,需要查找的关键字的全部信息都包含在叶子结点上。非终结点中只作为叶子结点关键字的索引而存在。

 

      查找对比:1. 在相同数量的待查数据下,B+树查找过程中需要调用的磁盘IO操作要少于普通B~树。由于B树所在的磁盘存储背景下,因此B+树的查找性能要好于B~树。

                    2. B+树的查找效率更加稳定,因为所有叶子结点都处于同一层中,而且查找所有关键字都必须走完从根结点到叶子结点的全部历程。因此同一颗B+树中,任何关键字的查找比较次数都是一样的。而B树就不一定了,可能查找到某一个非终结点就结束了。

 

      插入删除对比:  B+树与B~树在插入删除操作中的效率是差不多的。

 

      总体评价:在应用背景下,特别是文件结构存储中。B+树的应用要更多,其效率也要比B~树好。

 

字符串查找结构

 

这次专题所讲的BST、AVL、BRT、B~Tree等可以胜任对任何关键字数据进行查找。但对字符串的查找(字符串匹配)结构,有专门的结构和算法。详见:《KMP算法 》,《TrieTree 》

 

http://hxraid.iteye.com/blog/609312

http://www.icrazyhack.cn/wiki/index.php?title=%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91

http://blog.csdn.net/kay_sprint/article/details/6676488

http://blog.csdn.net/v_JULY_v/article/details/6530142

http://sjjg.js.zwu.edu.cn/SFXX/chazhao/chazhao7.3.2.html

http://dongxicheng.org/structure/red-black-tree/

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值