喜欢这篇文章吗?喜欢的话去看博主的置顶博客,即可依据分类找到此文章的原版得到更好的体验,

图片及代码显示的问题,笔者深感抱歉,想要更好的体验去原博文即可。


title: tree
mathjax: true
date: 2020-03-12 08:48:00
categories: [myself_library,datastructure,tree]
tags: [datastructure,tree]
keywords: [datastructure,tree]


总览

  这篇博客将用于整理各种树的数据结构,目前已经整理了BST、AVL、BTree、B+Tree、B*Tree、23Tree、234Tree、TTree、RBTree、LLRBTree、AATree、SplayTree、Treap、无旋Treap、scapegoatTree,VPTree、cartesianTree,

项目地址

链接

前置条件

  基本数据结构:变长数组、栈、队列、字符串的实现(此时暂未实现,使用STL代替,后面有时间会自己实现)
  内存池机制

树的设计

  我们设计一个基类让所有的树来继承此基类,然后在看后面会有什么改变,以后再来更新

基类

   我们的基类只提供接口,不提供数据类型

tree代码 {% include_code tree lang:cpp cpp/perfect/data_structure/tree.h %}

更新: 搜索树的设计

   由于笔者能力有限,设计欠佳,导致后面的空间树、字典树等数据结构无法加入tree中,所以我们在tree的后面加一层search_tree来表示搜索树。
  

搜索树代码 {% include_code tree lang:cpp cpp/perfect/data_structure/search_tree.h %}

binary search tree

BST是二叉搜索树,满足中序遍历是一个有序的序列,他是最最基础的二叉树,他不一定平衡,

BST insert

插入的时候,在树上递归插入,比当前节点大就向右边走,否则向左走

BST search

查找的时候,同上

BST erase

删除的时候,相对复杂,如果只有一个儿子,很简单,但是当他有两个儿子的时候,我们可以选择将一个儿子顶替自己,另外一个儿子去找前驱或后继即可。

BST code

我们使用内存池来维护整个数据结构

BST代码 {% include_code tree lang:cpp cpp/perfect/data_structure/binary_search_tree.h %}

AVL Tree

   AVL Tree使用高度差作为平衡因子,他要求兄弟的高度差的绝对值不超过1

code

avl Tree代码 {% include_code tree lang:cpp cpp/perfect/data_structure/avl_tree.h %}

B Tree

  B树是一颗多叉树,和二叉树比较类似,但是每个节点有多个子节点和多个键,通常我们称最多拥有N个子节点的B树为N阶B树,B树为了保证树的有序,树上节点的子节点数量恰好比键的数量多1,这就保证了存在一种方式将子节点和键排在一起,且每个键的左边、右边都是子节点,这样形成的序列即为维护的序列。

B Tree 约束

  B树的节点分三类,根节点、叶子节点、内部节点(除了根节点和叶子节点以外的节点)
  所有的叶子节点的深度相同,这一点保证树的平衡
  根节点的键的的数量在区间[2,N-1]上 , N>=3
  每个内部节点、叶子节点的键的数量在区间[⌈N2⌉−1,N−1][\lceil\frac{N}{2}\rceil-1,N-1][⌈2N​⌉−1,N−1]上
  每个节点的键的个数恰好比子节点个数多1

B Tree insert

  B树的插入很简单,找到应该插入的叶子节点,然后插入。这会可能导致树不符合约束->叶子节点上键的数量过多,此时叶子结点上的键的数量为N,这时候我们分裂叶子节点为两个叶节点,从中取出中位数置入父节点作为划分这两个叶子节点的键。我们很容易证明⌊N−12⌋≥⌈N2⌉−1\lfloor\frac{N-1}{2}\rfloor\ge\lceil\frac{N}{2}\rceil-1⌊2N−1​⌋≥⌈2N​⌉−1,若父节点依旧超出约束范围,同理向上继续对内部节点分裂,直道碰到根节点,若根节点依旧键的个数过多,则继续分裂,然后创建新的根节点将分裂出的节点连接。

B Tree erase

  B树的删除同普通平衡树一样,若删除点出现在内部节点或根节点中,我们取出他的前驱或后继将他替换。然后再删除。我们将所有情况合并到了删除叶子节点上。若删除后树依旧满足约束,则不需要调整。若不满足约束,根据N>=3我们得出每个节点最少两个子节点,若删除位置的兄弟节点有较多键,我们只需要从兄弟节点移动一个键过来即可。若兄弟节点同样处于最少键时,我们可以合并这两个节点2∗(⌈N2⌉−1)≤N−12*(\lceil\frac{N}{2}\rceil-1)\le N-12∗(⌈2N​⌉−1)≤N−1

B Tree search

  直接二分向下即可。

注意

  注意vector的 insert、erase后会导致的引用失效,

code

B Tree代码 {% include_code tree lang:cpp cpp/perfect/data_structure/B_tree.h %}

B+ Tree

   和B树一样,B+树也具有相同的性质。

不同点

   B+树的内部节点、根节点只保存了键的索引,一般情况下保存的是一个键指向的子树的所有键的集合中最大的那个,即所有左边子树的max,唯一的键保存在叶子节点上,
   叶子节点按照链表有序连接,这导致了B+树能够用链表来遍历整棵树。

B+树优点

   因为内部节点、根节点保存的是索引(指针),这导致单位储存空间储存的指针要比单位空间储存的键多得多,这同时导致了B+树能够比B树更加扁平。

代码

   这东西实现难度有点高,太码农了,我随缘实现吧。哈哈哈哈哈哈。

B* Tree

   B*树在B+树的基础上再把内部节点也整上链表,同时要求空间使用率为23\frac{2}{3}32​而不是12\frac{1}{2}21​

代码

   随缘

23tree

  参见3阶Btree

234tree

  参见4阶Btree

T tree

  T tree 是一颗二叉树,他和avl tree有着一定的联系,总所周知,avl树为一颗二叉树,利用其中序维护信息,利用子树高度维护平衡。我们借此修改一下,我们尝试让avl树的每个节点维护多个信息[信息序列],于是T tree就出现了。T tree是一颗二叉树,每个节点维护一个有序序列,用T 树的中序遍历方式,将其节点维护的序列依次相连即成为了我们维护的信息。

T tree 解释

  为了便于编码,我们不考虑序列中会出现相同的元素,可以证明,对于泛型编程方式而言,这并不影响该数据结构的功能,该数据结构依旧具备维护相同元素的能力

T tree结论

  非叶节点维护的序列都充满了各自的容器

T tree树上信息

  每一颗子树都要维护一个序列,对于每个节点,我们都维护一个稍微小一点的序列,比该序列中元素更小的元素放入左子树,否则放入右子树。

T tree搜索

  搜索的话,就是普通二叉树的搜索,比当前节点维护的最小值小,就在左子树找,比当前节点维护的最大值大,就在右子树找,否则就在当前节点找

T tree插入

  当我们插入一个数的时候,我们首先递归向下,找到插入的节点位置,若该节点中储存的序列未满,则置入该节点,否则,有两种处理方式,第一种是从该节点中取出最小值,放入左子树,然后把带插入的树放入该节点,第二种是放入右子树,这里不多说明。插入可能会导致树失去平衡,我们用avl树单旋的方式来让树重新平衡

T tree删除

  当我们删除一个数的时候,像avl树一样处理,若该数在叶子上,简单删掉并维护树的平衡即可,让该数在非叶节点时,我们取出前驱或后继来顶替即可。

T tree一个容易出错的地方

  笔者在编码的时候,遇到了一个问题,就是有时候会出现非叶节点维护的数据并未充满容器,这种情况发生的原因是单旋造成的。在单旋的时候,将叶子结点旋转成非叶节点后,我们应该调整数据,让非叶节点重新维护的数据充满容器

T treecode

TT代码 {% include_code tree lang:cpp cpp/perfect/data_structure/T_tree.h %}

red black tree

red black tree定义

  红黑树是一种平衡树,他满足下面的性质

1.节点是红色或黑色。
2.根是黑色。
3.所有叶子都是黑色(叶子是NIL节点)。
4.每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5.从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

red black tree解读性质

  红黑树的性质难以理解,这是因为他太过于抽象了, 如果你了解B Tree, 我们现在考虑节点中最多包含3个键的B Tree,他又叫2-3-4tree,意思是任何一个节点都有2,3或4个直接子孙,直接子孙指的是和当前节点相邻的子孙,相邻指的是恰好有一条边连接。
  2-3-4树的编码是比较复杂的,原因在于节点种类过多。我们现在考虑这样一种情况,RB tree中的红色节点代表他和他父亲在一起,即他+他的父亲构成了2key3son-node,若他的兄弟也是红色,则他+兄弟+父亲构成了3key4son-node
  性质1显然
  性质2的原因是根没有父亲,所以他不能为红
  性质3的原因是为了保证更具有一般性
  性质4的原因是保证最多只有3key4son-node,不能出现4key5son-node
  性质5的原因是B树的完全平衡性质

red black tree编码

  由此可见,我们仿照234Tree即BTree即可完成编码

为什么红黑树跑得快

  我们发现234树的所有操作都能在红黑树上表现,但是234树有一个很大的缺陷,即分裂合并的速度太慢了,要重构很多东西,细心的读者自己模拟会发现,这个过程在RBTree上对应的仅仅是染色问题,这极大的加速了数据结构,这是优势。

red black tree erase

  删除是比较复杂的,你怎样操作都可以,只要旋转次数少,你可以分很多类来讨论,显然分类越多,平均旋转次数是最少的。正常情况下,erase会引进一个重黑色的概念,这个概念的实际意义指的是该节点有一个0key1son的黑色父亲被隐藏了。

red black tree code

red black tree代码 {% include_code tree lang:cpp cpp/perfect/data_structure/red_black_tree.h %}

left leaning red black tree

left leaning red black tree定义

   在红黑树的基础上,左倾红黑树保证了3节点(2key-3son-node)的红色节点为向左倾斜,这导致了红黑树更加严格的定义,

left leaning red black tree实现

   在红黑树代码的基础上,我们定义一个left leaning函数,用来调整右倾斜为左倾斜,这个函数需要适当的加入到红黑树代码当中,笔者调试了很久,找到了很多思维漏洞,把这些漏洞全部用数学的方式严格证明以后,调用left leaning函数即可。

left leaning red black tree优点

   相比红黑树而言,笔者认为提升不大,真的,但是有人使用了很少的代码就实现了LLRBT,这也算一个吧,笔者是修改的红黑树,所以很难受,代码更长了。

left leaning red black tree code

left leaning red black tree代码 {% include_code tree lang:cpp cpp/perfect/data_structure/left_leaning_red_black_tree.h %}

AA Tree

   AA树真的很棒,虽然他没有普通红黑树那么厉害,但是AA树挺容易实现的,AA树是一棵右倾红黑树23树,注意! 这里是23树,不是234树。

AA树的由来

   Arne Andersson教授在论文Balanced search trees made simple中提到,红黑树有7种特殊情况(图片源于wiki)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Kz1WIk7-1584005377483)(\images\aa_tree\rb.png)]
   为了改进,他提出了使用23树并强行要求3节点(2key-3son-node)向右倾斜,于是,我们只剩下两种情况(图片源于wiki)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U7y0mZ3K-1584005377484)(\images\aa_tree\aa.png)]
   为了更加容易编码,他提出不再使用红黑来标识节点,而是选择高度,这里的高度指的是黑高度,即黑色节点的高度,学习过左偏树(左翼堆)或斜堆的读者应该对这里不太陌生,这里的高度其实和左偏树或斜堆中的右距离是同一个东西。

AA树的特性

所有叶节点的level都是1
每个左孩子的level恰好为其父亲的level减一
每个右孩子的level等于其父亲的level或为其父亲的level减一
每个右孙子的level严格小于其祖父节点的level
每一个level大于1的节点有两个子节点

AA树的skew

  skew 是一个辅助函数,他的本质是zig,即如果发现一个节点的左儿子与自己黑高相同,则将左儿子选择至根。这将保证右倾。

AA树中的split

   split同样是一个辅助函数,他的本质是zag,即如果发现一个节点的右孙子与自己黑高相同,则将右儿子选择至根,并将黑高+1,这将保证不会出现4节点(3key-4son-node)

AA树中的insert

   递归向下,找到插入位置,然后插入,最后调整,调整的时候,树会变高,对每一层递归而言,左儿子变高我们就先让其skew,这可能导致出现4节点,我们再split,对于右儿子变高的情况,这时候可能右儿子本身是一个3节点,当他变高,导致根成为了4节点,我们调用skew即可,全部统一一下,就是先skew后split

AA树中的erase

   很多时候删除都是一件困难的事情,但是我们可以通过寻找前驱后继,可以保证删除的节点一定是叶子,对于删除叶子,可能树高下降,同样的,先删除后对每一层进行调整。我们前面说过,AA树只有两种结构。我们来分析一下树高下降产生的影响。

情况1

   右儿子与自己同黑高

情况1.1

   右儿子下降

   这种情况是合法的,不需要调整

情况1.2

   左儿子下降

   我们观察到这里是一种较为复杂的情况,可以这样处理,让节点a和c同时黑下降,得到了

   然后我们考虑到c节点的左右儿子,注意到c和a以前黑同高,所以c的右儿子cr,一定比c矮,当c下降以后,cl、c、cr同高

   根据定义,这里最多还能拖出两个同黑高的,cl的右儿子clr,cr的右儿子crr

   这时候我们对c执行skew,然后clr成了c的左儿子,我们再次对c执行skew,最终a-cl-clr-c-cr-crr同黑高,

   接下来的一步是让我最吃惊的,非常漂亮,我们先对a进行split,然后对根的右儿子再次split,就结束了。对a进行split后我们得到,注意到这里根的高度提高了

   对根对右儿子split,就结束了

情况2

   右儿子与自己不同黑高

情况2.1

   右儿子下降

   让a节点高度降低

   让a进行skew,最后因为b的右儿子高度,分两种情况


   对于b的右儿子太高的时候,对a进行skew

   然后对b进行split即可

情况2.2

   左儿子下降

   让a下降

   这里可能发生c的右儿子与c同高,split(a)即可

AA树erase总结

   至此我们的删除已经讨论完了,实际细分只有4种情况,这要比普通红黑树简单多了,

AA树缺点

   多次旋转导致性能不及红黑树,旋转次数较多

AA树代码

AA树代码 {% include_code tree lang:cpp cpp/perfect/data_structure/aa_tree.h %}

splay tree

   伸展树,以其操作splay出名。
   伸展树的本质就是bst,

splay操作

   伸展树对splay操作的参数是一个节点,他的结果是将这个节点通过双旋变成根。

splay insert

   伸展树insert的时候,先按照bst的操作insert,然后将insert的点进行splay操作即可

splay search

   伸展树search的时候,先按照bst的操作search,对找到的节点进行splay即可

splay erase

   伸展树erase的时候,先search,这样我们要删除的节点就成为了根,然后按照bst的操作删除即可

splay操作详解

重新定义旋转rotate

   rotate(x)即交换x和x的父亲的位置,即如果x是父亲y的左儿子,则rotate(x)等价与zig(y),反之则等价于zag(y)

定义splay

   如果祖父-父亲-自己构成一条直链,则选rotate父亲再rotate自己,若不是直链则rotate自己两次。知道自己成为根。

splay复杂度分析

splay势能函数

   对于一个伸展树T,他的一个节点x的子树大小为s(x)s(x)s(x),定义一个节点x的势能为X=log2(s(x))X=log_2(s(x))X=log2​(s(x))

对数函数是一个凸函数

   已知a,b>0,则lg(a)+lg(b)<2lg(a+b2)=2lg(a+b)−2lg(a)+lg(b)\lt 2lg(\frac{a+b}{2}) = 2lg(a+b)-2lg(a)+lg(b)<2lg(2a+b​)=2lg(a+b)−2

对于一条直链,我们要先rotate父亲,再rotate自己

   设自己为x,父亲为y,祖父为z, 则势能变化为 $$ \begin{aligned} &X'+Y'+Z'-X-Y-Z \\&=Y'+Z'-X-Y\lt X'+Z'-2X \\&=(3X'-3X)+(X+Z'-2X') \end{aligned} $$   这里的x和z‘的子树大小加起来刚好等于x'的子树大小-1。所以势能变化小于$3(X'-X)-2$ ### 对于一条非直链,我们要rotate自己两次,才能上去,rotate父亲不行的    同理,势能变化为 $$ \begin{aligned} &X'+Y'+Z'-X-Y-Z \\&=Y'+Z'-X-Y\lt Y'+Z'-2X \\&=(2X'-2X)+(Y'+Z'-2X') \end{aligned} $$   这里的y'和z'的子树大小加起来刚好等于x‘的子树大小-1,所以势能变化小于$2(X'-X)-2$ ### 单旋    易证势能变化小于$X'-X$ ### 整理合并    三种操作的均摊复杂度分别为$O(1)+X'-X$,$O(1)+2(X'-X)-2$,$O(1)+3(X'-X)-2$,对于后面的两种情况,我们增大势的单位来支配隐藏在O(1)中的常数,最终分别为$O(1)+X'-X$,$2(X'-X)$,$3(X'-X)$,再次放缩: $O(1)+3(X'-X)$,$3(X'-X)$,$3(X'-X)$,最后对于所有的旋转求和,因为只有一次单旋所以最终我们得到了均摊复杂度为$O(1)+X'-X\lt O(1)+X'$,显然X'是一个很小的数,他恰好等于伸展树中的元素的个数取对数后的结果。至此所有的操作均取决于splay的复杂度,均为$lg$级别。 ## splay代码 splay树代码 {% include_code tree lang:cpp cpp/perfect/data_structure/splay_tree.h %}

Treap

   树堆Treap来源于Tree+Heap的组合, 其实就是一棵树,他的节点储存了两个键,一个是我们维护的信息,另外一个是随机数,我们不妨设前者叫key,后者叫rand_key,Treap的key满足搜索树的性质,Treap的rand_key满足堆的性质。(从某种意义上而言,笛卡尔树是key=rand_key的Treap)
   特点: 若key与rand_key确定后,Treap的形态唯一,
   Treap在大多数情况下显然是平衡的,但我不会证明,也没找到证明,暂时先放一下。

Treap insert

   我们向一棵Treap中按照搜索树的性质插入值以后,不会破坏搜索树的特点,但是大概率导致Heap的性质被违反。考虑到单旋不会导致搜索树的性质被破坏,我们通过单旋来从新让Treap满足Heap的性质。考虑回溯,假设我们对某个子树插入了一个值,若最终插入到左子树,则可能导致左子树树根的rand_key比当前节点的rand_key大,同时因为我们只插入了一个节点,所以最多也只有一个节点的rand_key比当前节点的rand_key大,这时候如果使用zig,则树恢复平衡。

Treap erase

   还是使用平衡树的操作来对Treap进行删除。如果过程中用到了前驱后继替换的技巧,这将导致替换节点的rand_key和他所处在为位置不匹配,我们就只考虑这颗子树,因为只有这颗子树的树根出现了问题,我们尝试递归向下,将位置不匹配这个现象下移,因为不匹配,必然是这个节点的rand_key比儿子们小,这时候如果左儿子的rand_key大就zig,否则zag,最后能发现这问题在向叶子结点转移,我们能够递归向下,直到最后转移到叶子上,树就恢复平衡了。

Treap 代码

Treap代码 {% include_code tree lang:cpp cpp/perfect/data_structure/treap.h %}

无旋Treap

   无旋treap,指的是不使用zig和zag来重新恢复平衡的Treap
   我们使用merge和split

无旋Treap merge

   merge的参数是两个treap,他返回treap合并后的结果,不妨设其中一个为T1,另一个为T2,这里还要求T1的最大key小于等于T2的最小key。merge其实很简单,如果你学过左偏树的话,会很容易理解。我们不妨设T1的根的rand_key比T2的小。那么很显然,最终结果的根为T2的根,这里我们就可以递归了,我们将T2的左子树与T1合并出T3,最后让T3最为T2新的左子树,我们得到的T2就是merge的结果。

无旋Treap split

   split的参数是一个Treap和一个值W,他返回两颗Treap,其中一个的最大key小于W,另一个大于W(不需要考虑等于的情况),这个过程依然很简单,我们考虑根就可以了,如果根的key大于w,则根和右子树分到一遍,然后递归左儿子,将得到的两个Treap中key大的那个作为之前分到一边的根的左儿子即可。

无旋Treap insert

   先split,然后merge两次

无旋Treap erase

   很多人这里使用了split两次然后merge三次,我认为这个不太好,常数过大,我们可以这样做,先search找到要删的点,然后merge其左右子树顶替自己即可。

无旋Treap代码

无旋Treap代码 {% include_code tree lang:cpp cpp/perfect/data_structure/no_rotate_treap.h %}

scapegoat Tree

   替罪羊树,他是一个暴力的bst,与普通bst相比,他记录了子树的大小,用参数alpha来定义平衡,即左右子树的大小都不允许超过根的alpha倍,所以往往aplha是一个0.5到1的数字,当违反了这个性质,就暴力重构,将树构造为完全平衡树。

替罪羊树erase

   为节点打上标记scapegoat,代表这个节点已经被删除了,回溯子树大小信息。

替罪羊树insert

   使用bst插入的方式来插入,注意特判掉那些被打删除标记的点,就可以了

替罪羊树重构

   当我们erase或者insert以后,受影响的节点应该恰好构成了一条从根到目标的链,我们使用maintain来重新调整子树大小的时候,注意标记那些非法(不平衡)的节点,然后当我们maintain到根的时候,我们重构离根最近的不平衡的子树。

替罪羊树代码

替罪羊树代码 {% include_code tree lang:cpp cpp/perfect/data_structure/scapegoat_tree.h %}

vantate point tree

  vp tree 是一颗二叉树,他和kd tree有着一定的相似度,

树上信息

  每一颗子树都要维护一个点集,对于每个节点,我们都维护一个距离d,然后将到该节点的距离小于d的点放到左儿子,其他的放到右儿子中。

vantate point

  vantate point的选取是一个比较麻烦的事情,我们仔细想想都知道,这个点的选取肯定会影响算法,有一种处理办法是随机选取,这显然不是我们想要的。我们其实可以这样来处理,

Our algorithm constructs a set of vantage point candidates by random sampling,and then evaluates each of them.Evaluation is accomplished by extracting another sample,from which the median of ∏p(S)\prod_p(S)∏p​(S),and a corresponding moment are estimated.Finally,based on these statistical images,the candidate with the largest moment is chosen.

  这里的∏p(S)\prod_p(S)∏p​(S)指的就是在该度量空间中点p和点s的距离,作者选取的statistical images是方差,我们可以从伪码中看出。

建树

  和kd树一样,建树的过程是一致的,我们选出vantate point,然后递归左右建树

搜索

  搜索的话,也是一样的,用结果剪枝即可

修改

  这样的树不存在单旋这种方式,我们只能用替罪羊树套vantate point tree来实现

参考资料

Data Structures and Algorithms for Nearest Neighbor Search in General Metric Spaces Peter N.Yianilos*

cartesian tree

笛卡尔树是一颗二叉树,他满足中序遍历为维护的序列,且满足堆的性质

build

我们使用单调栈来维护树根到叶子的链,在单调栈的构建中完成树的构建

ct代码 {% include_code tree lang:cpp cpp/perfect/data_structure/cartesian_tree.h %}

BST、AVL、BTree、B+Tree、B*Tree、23Tree、234Tree、TTree、RBTree、LLRBTree、AATree、SplayTree、Treap、无旋Treap、scap相关推荐

  1. 转帖:BTree,B-Tree,B+Tree,B*Tree都是什么

    BTree,B-Tree,B+Tree,B*Tree都是什么 转帖自:http://blog.csdn.net/manesking/archive/2007/02/09/1505979.aspx &l ...

  2. [置顶]B-tree/B+tree/B*tree [转]

    (原文出处: http://blog.csdn.net/hbhhww/article/details/8206846) B~树 1.前言: 动态查找树主要有:二叉查找树(Binary Search T ...

  3. BST AVL 红黑树 B B+树

    二叉搜索树(BST) 简明BST递归定义(Knuth Donald): 对于任意一个节点均满足: 1. 所有位于左子树的节点值均比该节点值小 2. 所有位于右子树的节点值均大于等于该节点值 3. 所有 ...

  4. 3. 数据结构--二叉树 BST AVL树 Huffman

    数据结构–二叉树 KEY:(不敢相信没有堆-) 二叉树的定义及其主要特征 ☑️ 二叉树的顺序存储结构和链式存储结构实现 二叉树的遍历及应用 二叉排序(查找.检索)树 (BST) 平衡的二叉检索树- A ...

  5. # tree bash: tree: 未找到命令...

    今天使用CentOS7想查看tree,现象如下: [root@localhost 桌面]# tree bash: tree: 未找到命令- 显示找不到命令,后来发现原因是部分linux系统没有tree ...

  6. BTree,B-Tree,B+Tree,B*Tree

    B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: B ...

  7. 关于索引的B tree B-tree B+tree B*tree 详解结构图

    2019独角兽企业重金招聘Python工程师标准>>> B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结 ...

  8. 关于索引的B tree B-tree B+tree B*tree 详解结构图

    B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: B ...

  9. B-tree/B+tree/B*tree

    转载:http://blog.csdn.net/hbhhww/article/details/8206846 转载于:https://www.cnblogs.com/wrencai/p/4890189 ...

最新文章

  1. C语言 #ifndef 引起的redefinition of xxx 问题解决
  2. Win32开发之Format MessageBox 详解
  3. 使用python进行utf9编码和解码
  4. Python 技术篇-1行代码实现语音识别,speech库快速实现简单的语音对话
  5. 离散哈特莱变换(DHT)及快速哈特莱变换(FHT)学习
  6. MSTP多业务传输平台对设备接口的要求有哪些?
  7. go语言基础之工程管理和工作区介绍
  8. 比较=、==、===
  9. Python 进阶篇
  10. win10系统恢复win7的照片查看器
  11. 第3.3节 通过GPIB控制矢量网络分析仪
  12. 利用布尔运算可以做出怎样的PPT特效
  13. android 隐藏电池,Android8.1隐藏状态栏电池图标
  14. python stdin.write_向stdin写入大量数据
  15. 再见2018,感谢你的一路陪伴
  16. 点亮LED灯(LED)
  17. Python基础笔记(二)整数缓存、字符串驻留机制、字符串格式化等
  18. 方舟编译器将开源!华为邀广大开发者助力鸿蒙系统
  19. EXCEL进度管理很好用的模板
  20. 斗地主检测牌型(玩家)

热门文章

  1. 使用Arduino开发板进行语音识别
  2. stm32的语音识别_基于STM32的嵌入式语音识别模块设计实现
  3. 一种崭新的长尾分布下分类问题的通用算法|NeurIPS 2020
  4. k/3 Cloud如何从菜鸟成长一名合格的ERP开发工程师
  5. 项目管理(PMP)项目经理的角色
  6. 清空input的type为file时的值
  7. 达梦数据库和mysql索引引擎_达梦数据库如何建索引和使用
  8. 对字符串进行信道编码C语言,【单选题】PCM编码主要用于实现模拟信号数字化,它属于( ) A. 信道编码 B. 纠错编码 C. 信源编码 D. 压缩编码...
  9. BFT-SMaRt:用Netty做客户端的可靠信道
  10. 分布式任务调度框架和微服务的区别