吐血整理:二叉树、红黑树、B&B+树超齐全,快速搞定数据结构
前言
没有必要过度关注本文中二叉树的增删改导致的结构改变,规则操作什么的了解一下就好,看不下去就跳过,本文过多的XX树操作图片纯粹是为了作为规则记录,该文章主要目的是增强下个人对各种常用XX树的设计及缘由的了解,也从中了解到常用的实现案例使用XX树实现的原因。
数据在计算机中的存储结构主要为顺序存储结构、链式存储结构、索引存储结构、散列存储结构,其中链式存储结构最常见的示例是链表与树,链式存储结构主要有以下特点:
优点:逻辑相邻的节点物理上不必相邻,插入、删除灵活,只需改变节点中的指针指向
缺点:存储空间利用率低,需通过指针维护节点间的逻辑关系;查找效率比顺序存储慢
度:当前节点下的子节点个数
推荐学习:MySql从入门到“入坟”系列:阿里大牛用300分钟带你彻底了解MySQL的各种底层实现机制(MySql索引、MySql事务、MySql锁机制等)
二叉树
二叉树是每个节点最多有两个子树的树结构,左侧子树节点称为“左子树”(left subtree),右侧子树节点称为“右子树”(right subtree)。每个节点最多有2个子节点的树(即每个定点的度小于3)。
二叉树的特点
至少有一个节点(根节点)
每个节点最多有两颗子树,即每个节点的度小于3。
左子树和右子树是有顺序的,次序不能任意颠倒。
即使树中某节点只有一棵子树,也要区分它是左子树还是右子树。
满二叉树
除了叶子节点外每一个节点都有两个子节点,且所有叶子节点都在二叉树的同一高度上。
完全二叉树
如果二叉树中除去底层节点后为满二叉树,且底层节点依次从左到右分布,则此二叉树被称为完全二叉树。
二叉查找树(Binary Search Tree - BST,又称二叉排序树、二叉搜索树)
二叉查找树根节点的值大于其左子树中任意一个节点的值,小于其右子树中任意一节点的值,且该规则适用于树中的每一个节点。
二叉查找树的查询效率介于O(log n)~O(n)之间,理想的排序情况下查询效率为O(log n),极端情况下BST就是一个链表结构(如下图),此时元素查找的效率相等于链表查询O(n)。
二叉查找树需要注意的是删除节点操作时的不同情况,删除节点根据节点位置会有以下三种情况:
删除节点的度为0,则直接删除
删除节点的度为1,则该子节点替代删除节点
删除节点的度为2,则从左子树中寻找值最大的节点替代删除节点。对树结构改动最少、节点值最进行删除节点值的必然是左子树中的最大叶子节点值与右子树中的最小叶子节点值
为什么不用右子树中的最小叶子节点值取代删除节点?个人认为是为了维持范围值(纯属臆测):
右子树中的最小叶子节点值大于删除节点左子树中的所有节点,但若该叶子节点比删除节点大很多,这将会大大扩大左子树的范围值,左子树可插入的范围值也会大大增大,对左子树的查询效率造成较大的影响 左子树中的最大叶子节点值也大于删除节点左子树中其它所有的节点,虽然是使用该节点替代删除节点会缩小的左子树的值范围,但也减少左子树的插入范围值,对左子树的查询影响不大
由上可以看出,二叉查找树(BST)无法根据节点的结构改变(添加或删除)动态平衡树的排序结构,也因此对某些操作的效率造成一定的影响,而AVL树在BST的结构特点基础上添加了旋转平衡功能解决了这些问题。
平衡二叉搜索树 (Balanced binary search trees,又称AVL树、平衡二叉查找树)
AVL树是最早被发明的自平衡二叉搜索树,树中任一节点的两个子树的高度差最大为1,所以它也被称为高度平衡树,其查找、插入和删除在平均和最坏情况下的时间复杂度都是O(log n)。
平衡二叉搜索树由Adelson-Velskii和Landis在1962年提出,因此又被命名为AVL树。平衡因子(平衡系数)是AVL树用于旋转平衡的判断因子,某节点的左子树与右子树的高度(深度)差值即为该节点的平衡因子。
AVL树的特点
具有二叉查找树的特点(左子树任一节点小于父节点,右子树任一节点大于父节点),任何一个节点的左子树与右子树都是平衡二叉树
任一节点的左右子树高度差小于1,即平衡因子为范围为[-1,1] 如上左图根节点平衡因子=1,为AVL树;右图根节点平衡因子=2,固非AVL树,只是BST。
为什么选择AVL树而不是BST?
大多数BST操作(如搜索、最大值、最小值、插入、删除等)的时间复杂度为O(h),其中h是BST的高度。对于极端情况下的二叉树,这些操作的成本可能变为O(n)。如果确保每次插入和删除后树的高度都保持O(log n),则可以保证所有这些操作的效率都是O(log n)。
节点插入、旋转
AVL树插入节点的如下:
根据BST入逻辑将新节点插入树中
从新节点往上遍历检查每个节点的平衡因子,若发现有节点平衡因子不在[-1,1]范围内(即失衡节点u),则通过旋转重新平衡以u为根的子树
旋转的方式:
左旋转:用于平衡RR情况,对失衡节点u(unbalanced)及子树进行左旋
右旋转:用于平衡LL情况,对失衡节点u及子树进行右旋
左右旋转:用于平衡LR情况,对失衡节点失衡u的左子节点ul左旋,再对失衡节点u右旋
右左旋转:用于平衡情况,对失衡节点u失衡方向的右子节点ur右旋,再对失衡节点u左旋
LL - 插入节点是失衡节点u左子节点ul上的左子树节点
gif图中的高度是从叶子节点开始计算的,因为插入节点后是从下往上检测节点的平衡因子,所以叶子节点高度恒为1更方便平衡因子的运算
LR - 插入节点是失衡节点u左子节点ul上的右子树节点
RR - 插入节点是失衡节点u右子节点ur上的右子树节点
RL - 插入节点是失衡节点u右子节点ur上的左子树节点
规律总结:
失衡节点到其最底部叶子节点的高度不会超过4
失衡节点哪里不平衡就会往哪里的反向旋转
添加的节点到失衡节点的路径如果是一条直线(即LL或RR),则只需对失衡节点u进行反向旋转
添加的节点到失衡节点的路径如果是一条曲线(即LR或RL),则需先对该路径上失衡节点u的子节点(ul/ur)进行旋转,再对失衡节点进行旋转
失衡节点u旋转后会成为它原来子树(ul/ur)中的一颗子树,如果u旋转时替代u的子树已有u旋转方向上的子树,那么该子树会断裂成为u的子树(如下LR的u右旋,uls已有右子树T2,故会T2断裂以BST的规则重新插入成为u的子树)
u u uls
/ \ / \ / \
ul T3 Left Rotate (us) uls T3 Right Rotate(u) ul u
/ \ - - - - - - - - -> / \ - - - - - - - -> / / \
T1 uls ul T2 T1 T2 T3
\ /
T2 T1
节点删除步骤
对删除节点D根据BST规则执行删除
选择平衡,该步骤与插入区别不大,从D节点往上遍历检查每个节点的平衡因子,若发现有节点失衡,则通过旋转重新平衡以u为根的子树
例子
根据BST规则删除节点133,155替代133位置
从155位置往上检测到100为失衡节点u,左高右低为LR情况,对u左子节点ul=37左旋,再对u节点执行右旋(可以看成对50同时插入2个子节点导致100节点失衡)
AVL树伪代码
AVLTree{
private Node root;
private class Node{
// height从叶子节点开始计算(即叶子节点恒为1,方便遍历父节点的平衡因子计算)
int val,height;
Node left;
Node right;
public Node(int val){
height = 1;
this.val = val;
}
}
public void insert(int val){
if(root == null){
root = new Node(val);
} else {
insert(root, val);
}
}
/**
* 将值val按AVL规则插入到节点树node下
* 1. 根据BST规则遍历插入val节点,更新插入经过的路径上的节点高度
* 2. 检测是否有失衡节点,没有失衡则直接设置高度,失衡则旋转再调整高度
* @param node 插入节点到node子树
* @param val 插入的节点值
*/
private insert(Node node, Integer val);
/**
* 获取节点的失衡因子:left.height - right.height
*/
int getBalance(Node node);
/**
* 节点左旋,调整旋转的节点高度height
*/
leftRotate(Node node);
/**
* 节点右旋,调整旋转的节点高度height
*/
rightRotate(Node node);
}
红黑树(Red - Black Tree)
红黑树是一种自平衡二叉搜索树(BST),且红黑树节点遵循以下规则:
每个节点只能是红色或黑色
根节点总是黑色的
红色节点的父或子节点都必然是黑色的(两个红色的节点不会相连)
任一节点到其所有后代NULL节点的每条路径都具有相同数量的黑色节点
每个Null节点都是黑色的
相比AVL树
AVL树比红黑树更加平衡,但AVL树可能在插入和删除过程中引起更多旋转。因此,如果应用程序涉及许多频繁的插入和删除操作,则应首选Red Black树(如 Java 1.8中的HashMap)。如果插入和删除操作的频率较低,而搜索操作的频率较高,则AVL树应优先于红黑树。
个人引申的疑问
为什么红黑树也算平衡树呢?它的平衡因子是什么?
为什么AVL比红黑树更平衡?为什么AVL树插入和删除会引起更多选择呢?
原因可从后续的插入步骤与演示案例得出
插入节点
红黑树插入节点后违反的主要规则是两个连续的红色节点。
插入步骤:
将新节点n根据BST规则插入,且新使节点颜色为红色
根据n的父节点p情况执行不同的操作 2.1 n没有父节点p,即N为根,将n的颜色更改为黑色 2.2 p为黑色,直接插入 2.3 p为红色,则根据不同的情况执行操作 2.3.1:n的uncle节点u是红色(uncle节点:父节点p父节点下的另一节点|n祖父节点g的另一子节点) a. 将节点p与节点u改为黑色 b. 将g的颜色改为红色 c. 将祖父节点g当成节点n,对n重复b、c步骤 2.3.2:n的uncle节点n是黑色,则会有以下案例(类同AVL树,g=avl.u,p=avl.ul|ur): LL:p是g左节点,x是p的左节点,对g进行右旋 LR:p是g的左节点,x是p的右节点 RL:p是g的右节点,x是p的右节点 RR:p是g的右节点,x是p的左节点 调整旋转了的节点颜色
检查根节点,根节点为红色则染黑
演示案例
插入12:父节点25是红色节点,uncle节点75是红色节点,属插入的2.3.1情况,将父节点25改为黑色,将祖父节g点改为红色,最后将根节点g即改为黑色
插入35:父节点25是黑节点,属2.2,直接插入
插入42:父节点35是红色节点,uncle节点12是红色节点,属2.3.1,将父节点35改为黑色,祖父节点25改为红色,根节点保持黑色
插入38:父节点42是红色节点,uncle节点是黑色的空节点,属2.3.2,42(p)是35(g)的右节点,38(n)是42的左节点,为RL情况,对42(p=avl.ur)右旋,再对35(g=avl.u)左旋
引申疑问自答
红黑树是根据节点的值与颜色维持平衡的,即可把颜色看成平衡因子,所以即使左右子树的高度差>=2也不一定像AVL树一样为了保持平衡而旋转
AVL树的结构主要是围绕节点值与左右子树高度来保持平衡的,从节点值的角度考虑自然比红黑树更平衡,且值搜索时AVL的效率更高,但插入与删除较多时AVL树旋转操作会比红黑树更多,效率自然更慢
以上也是Java 8的HashMap中树节点实现结构采用红黑树而不是AVL树的原因
删除节点
删除节点主要违反的规则是子树中黑色高度的更改,导致根节点到叶子路径的黑色高度降低。
红黑树删除是一个比较复杂的过程,为了更容易的理解删除过程,可以使用双黑概念去简化理解该过程。 双黑概念指当删除黑色节点后使用了另一个黑色节点替代删除节点的位置(也可以当成有两个null的黑色叶子节点因删除重叠成1个),这也意味着根节点到替代节点的原路径上少了一个黑色节点导致违反了到任一叶子节点路径上含相同的黑色节点数的节点规则(黑色)。当删除时出现双黑情况,则需要通过旋转将节点转换为单黑色(重叠的两个黑色null节点重新铺展为2个)。
删除步骤
执行标准的BST删除,设删除节点为d(delete),替代节点为r(replace)
如果替换节点r或删除节点d其中一个为红色,则将替换节点r标记为黑色(因d是r的父级,红黑树不允许两个连续红色节点),结束删除流程,否则进行步骤3
r和d都是黑色,则按以下步骤进行操作 3.1 将r涂为双黑色(注:如果d是含值叶子节点,那么Null节点替代也是双黑) 3.2 若r不是根节点,设d的同级兄弟节点为b(brother,类似avl.ul|avl.ur),b的父节点为p(parent,类似avl.u),根据以下三种不同的情况进行相应的操作: d兄弟b是黑色,且b至少有1个红色的子节点,则对b进行旋转(规律类同)。设b的红色子节点为r(类似avl的插入节点),根据b和r的位置,可以将这种情况分为四个子情况(LL、LR、RL、RR): LL:b是其父节点(类似avl.u)的左子节点(类似avl.ul),r是b的左子节点或b的两个子节点都是红色,则对p进行右旋 LR:b是其父节点的左子节点(类似avl.ul),r是b的右子节点,则对b进行左旋,再对p进行右旋 RR:b是其父节点的右子节点(类似avl.ur),r是b的右子节点,则对p进行左旋 RL:b是其父节点的右子节点(类似avl.ur),r是b的左子节点,则对b进行右旋,再对p进行左旋 d兄弟b是黑色,且b的子节点都是黑色,则执行重新着色 a. 如果父节点是黑色的,则由父节点开始往下重新着色 b. 如果b父节点p是红色的,则不需要为p之前的节点重新着色,只需将节点p改为黑色(红+双黑=单黑) d兄弟b是红色,则将b向上移动(b左旋或右旋),并为b与父节点重新p着色 如果正常顺序添加上图节点删除节点d的兄弟b只会是黑色,需对其子节点添加一节点再删除添加的节点是可使b变红。 3.3 如果以上操作后u为根,则将其设为黑色,然后返回(完整树的黑色高度减少1)。
B-Tree(B树)
大多数自平衡搜索树(如AVL和红黑树)都会假定所有数据都在主内存中,但我们必须考虑无法容纳在主内存中的大量数据。当键的数量很大时,将以块形式从磁盘读取数据,与主存储器访问时间相比,磁盘访问时间非常高。 B树是一种自平衡搜索树,设计的主要思想是减少磁盘访问次数。大多数树操作(增、删、查、最大值、最小值等)都需要都需要O(h)磁盘访问,h为树的高度。B树通过在节点中放置最大可能的键来保持B树的高度较低。通常,B树节点的大小保持与磁盘块大小相等。由于B树的高度较低,因此与平衡的二叉搜索树(如AVL树、红黑树等)相比,大多数操作的磁盘访问次数显著减少。
磁盘块是一个虚拟的概念, 是操作系统(软件)中最小的逻辑存储单位,操作系统与磁盘打交道的最小单位是磁盘块。
一颗m阶(m指一个节点中最多包含的子节点数)B树特点如下:
所有叶子处于同一水平位置
除根节点外的每个节点都必须至少包含m/2-1个key,并且最多具有m-1个key,除根以外的所有非叶子节点必须至少具有m/2个子节点
节点的子节点数等于节点的key数加1
节点的所有key都按键值升序排序,两个键k1和k2之间的子key包含k1和k2范围内的所有键
与其他平衡二叉搜索树一样,搜索、插入和删除的时间复杂度为O(log n) p.s:B树由术语最小度t定义,t的值取决于磁盘块的大小,数值上m = 2t。
搜索
B-树搜索类似于搜索二叉树,算法与递归算法相似。在B树中,搜索过程也是从根节点开始,通过与节点key值比较进行搜索,搜索操作的时间复杂度为O(log n)。具体的搜索步骤如下:
将搜索值与树中根节点的第一个key进行比较
匹配则显示“找到给定节点”并结束搜索,否则进入步骤3
检查搜索值是大于还是小于当前key值 搜索值小于当前key:左子树中获取第一个key进行比较,重复2、3步骤 搜索值大于当前key:将搜索值与同一节点中的下一个key进行比较,重复2、3步骤,直到精确匹配,或搜索值与叶子节点中的最后一个key值相比较
如果叶节点中的最后一个键值也不匹配,则显示“找不到元素”并结束搜索
插入
设B树的阶为m,则插入流程如下:
如果树为空,则创建一个具有新键值的新节点,并将其作为根节点插入到树中,结束插入流程。
如果树不为空,则从根节点开始根据BST逻辑找到适合添加新键值的节点P,根据节点P的键空间情况(key数量 < m - 1,则key未满)进行不同的操作 2.1 节点P键未满:将新元素由小到大升序排序的方式添加到节点P的key中,结束插入流程 2.2 节点P键已满,则根据P是否为根节点进行相应的操作: a. 节点P非根节点:向父节点插入P的key中间值来拆分节点P(中间值按最小的发送),重复该操作,直到将发送值固定到节点中为止。若发送到根节点使根节点键溢出,则执行步骤b b. 节点P为根节点:根节点P的中间key值将成为树的新根节点,该key左右的key值成为根节点的左右子树,树的高度将增加一
4阶B树插入示例
以下示例皆为4阶B树(m=4),则有以下规则:
4阶B树的每个节点的最多key数目为3,最小key数目为1(m = 4, max_key_num = m - 1 =3, min_key_num = m/2 - 1 =1)
除根节点外的每个节点至少包含2个子节点,最多包含4个子节点(m = 4, min_sub_num = m/2 = 2)
插入流程 2.1 & 2.2.b 示例
插入125(插入流程2.1):根节点P未满,按升序将50插入到P
插入50(插入流程2.2.b):根节点P已满,将最小的中间值100独立为新的根节点,小于100的成为左子树,大于100的成为右子树
插入流程2.2.a 示例
插入115,插入节点后键溢出,取中间值114插入到父节点
根节点key数量溢出,取中间值112成为新的根节点,小于112的key作为112根节点的左子节点,大于112的key作为112根节点的右子节点,原插入节点位置的水平子树成为根节点左右子节点的子节点
删除
B树的删除比插入要复杂得多,因为我们可以从任何节点(不仅是叶子)中删除key,而且从内部节点删除key时,我们将不得不重新排列节点的子节点。 从B树中删除键的各种情况(设删除键k所在节点为n):
k所在节点n为树中节点(非叶子节点也非根节点),则根据以下不同的情况执行子节点key上移或合并完成删除操作 a. 节点n中在k之前的子节点kln(key left node)键数至少有m/2个,则在kln节点中查找最接近k的键k0,将k0替换k,结束删除操作。图例:m=4, m/2=2 , 删除k=75,k0=55 b. 节点n中在k之前的子节点kln键数少于m/2个,且k后的子节点krn(key的右侧节点)键数至少有m/2个,则在krn节点中查找最接近k的键k0,将k0替换k,结束删除操作。图例:m=4, m/2=2 , 删除k=55,k0=88 c. nkl与nkr键数都少于m/2个,则合并nkl与nkr为一个节点,删除k,结束删除操作。图例:m=4, m/2=2 , 删除k=99, k左侧与右侧子节点都小于m/2=2,合并两个子节点45与100
k所在节点n为叶子节点,则根据叶子节点n的key数是否少于m/2进行不同的删除操作 2.1 n.key数 >= m/2:则直接删除k(B树非根节点需至少包含m/2-1个key),结束删除流程。图例:m=4,m/2=2,删除k=5,所在节点n,key数=2,删除后节点key数为1,符合至少m/2-1个key规则 2.2 n.key数 < m/2 , 即n.key数=m/2 -1:删除key,删除后检查父节点与同父节点的相邻节点key数目进行相应的节点迁移以确保所有节点符合至少m/2-1个key规则,。 2.2.1 n的左侧节点nl.key数 >= m/2:取删除key指向的父节点左侧key下移到删除key位置,从n的左侧节点取最大的key上移到父节点np.key位置 2.2.2 n的左侧节点nl.key数 < m/2且右侧节点nr.key数 >= m/2:取删除key指向的父节点右侧key下移到删除key位置,从n的右侧节点取最小的key上移到父节点np.key位置,相当于2.2.1的镜像操作 2.2.3 nl.key数 < m/2 && nr.key数 < m/2 && np.key数 >= m/2:取删除key指向的父节点左侧key下移到删除key位置,将节点n与nl合并,若n为父节点下的最左侧节点,则n与nr合并。 2.2.4 nl.key数 < m/2 && nr.key数 < m/2 && np.key数 = m/2 -1:最麻烦的一种情况,具体步骤如下。 a. 取删除key指向的父节点np.key下移到删除key位置,将节点n与同父节点np下的相邻节点合并 b. 下移后父节点np.key数必然少于m/2-1,np从其父节点ng获取最接近下移np.key的键ng.key c. ng.key下移后会导致ng与np节点的相连key缺失,根据BST规则父节点的key比np及其子节点下的key值都要大或都要小,从np同父节点ng下的key数>2的相邻节点且npb(先左后右)取靠近np一侧的npb.key替代ng的缺失key;若npg.key数 < m/2,则将npg与n节点合并,结束删除流程,反之进入步骤c d. npb的key上移到ng后同样会使key缺失,n节点合并后也会导致np的子节点缺1,将npb缺失key连接的节点迁移到np缺失的子节点位置。若ng出现与np的情况,则以操作np的方式往上递归操作ng。
B+ Tree(B+树)
实现动态多级索引时,通常会采用B树和B+树的数据结构。但是,B树有一个缺点是它将与特定键值对应的数据指针(指向包含键值的磁盘文件块的指针)以及该键值存储在B树的节点中。该设计大大减少了可压缩到B树节点中的条目数,从而增加了B树中级别数与记录的搜索时间。 B+树通过仅在树的叶节点处存储数据指针来消除上述B树的缺点,因而B+树的叶节点结构与B树的内部节点结构完全不同。数据指针在B+树中仅存在于叶节点,因此叶节点必须将所有键值及其对应的数据指针存储到磁盘文件块以便访问。此外,叶节点也用于链接以提供对记录的有序访问。因此,叶节点才是第一级索引,而内部节点只是索引到其它级别索引的多层索引。叶节点的一些键值也出现在内部节点中,主要是作为简化搜索记录的一种媒介。 B+树与具有同级的B树相比,具有同级的B+树可以在其内部节点中存储更多键,显着改善对任何给定关键字的搜索时间,同样的键数B+树级别较低且含指向下一个节点的指针P的存在使B+树在从磁盘访问记录时非常快速有效。如设B树与B+树某一级别内部节点都有100K的容量,由于B树的节点除了存键和数据指针,所以实际存的键容量连一半50K可能都没有,但B+树的100K容量都用于存键了,所以索引自然更高效。
B树与B+树的区别
XX树实现案例
B-Tree缘由:大多数自平衡搜索树(如AVL和红黑树)都会假定所有数据都在主内存中,但我们必须考虑无法容纳在主内存中的大量数据。当键的数量很大时,将以块形式从磁盘读取数据,与主存储器访问时间相比,磁盘访问时间非常高。
结语
搞图搞得最多最耗时的一次笔记如有错误,还请指出。
吐血整理:二叉树、红黑树、B&B+树超齐全,快速搞定数据结构的更多相关文章
- 二叉树、红黑树、伸展树、B树、B+树
好多树啊,程序猿砍树记,吼吼. 许多程序要解决的关键问题是:快速定位特定排序项的能力. 第一类:散列 第二类:字符串查找 第三类:树算法 树算法可以在辅助存储器中存储大量的数据. 二叉树.红黑树和伸展 ...
- 数据结构(一)二叉树 & avl树 & 红黑树 & B-树 & B+树 & B*树 & R树
参考文档: avl树:http://lib.csdn.net/article/datastructure/9204 avl树:http://blog.csdn.net/javazejian/artic ...
- 二叉树、平衡二叉树、红黑树、B树、B+树与B*树
转: 二叉树.平衡二叉树.红黑树.B树.B+树与B*树 一.二叉树 1️⃣二叉查找树的特点就是左子树的节点值比父亲节点小,而右子树的节点值比父亲节点大,如图: 基于二叉查找树的这种特点,在查找某个节点 ...
- 红黑树、B(+)树、跳表、AVL等数据结构,应用场景及分析,以及一些英文缩写
在网上学习了一些材料. 这一篇:https://www.zhihu.com/question/30527705 AVL树:最早的平衡二叉树之一.应用相对其他数据结构比较少.windows对进程地址空间 ...
- 红黑树和AVL树的实现与比较-----算法导论
一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以 ...
- 红黑树与AVL树
概述:本文从排序二叉树作为引子,讲解了红黑树,最后把红黑树和AVL树做了一个比较全面的对比. 1 排序二叉树 排序二叉树是一种特殊结构的二叉树,可以非常方便地对树中所有节点进行排序和检索. 排序二叉树 ...
- B树、B+树、红黑树、AVL树
定义及概念 B树 二叉树的深度较大,在查找时会造成I/O读写频繁,查询效率低下,所以引入了多叉树的结构,也就是B树.阶为M的B树具有以下性质: 1.根节点在不为叶子节点的情况下儿子数为 2 ~ M2. ...
- Linux内核之于红黑树and AVL树
为什么Linux早先使用AVL树而后来倾向于红黑树? 实际上这是由红黑树的有用主义特质导致的结果,本短文依旧是形而上的观点.红黑树能够直接由2-3树导出.我们能够不再提红黑树,而仅仅提2- ...
- AVL树、红黑树以及B树介绍
简介 首先,说一下在数据结构中为什么要引入树这种结构,在我们上篇文章中介绍的数组与链表中,可以发现,数组适合查询这种静态操作(O(1)),不合适删除与插入这种动态操作(O(n)),而链表则是适合删除与 ...
随机推荐
- Go的100天之旅-04基础数据类型
基础数据类型 在变量的定义中,我们讲了每个变量是有类型的,类型在计算机中是用来约束数据的解释.Go语言和其它计算机语言一样,提供丰富了丰富的数据类型,我们就来看看到底有哪些类型,同时也可以比较一下它和 ...
- mybatis自动生成代码插件mybatis-generator使用流程(亲测可用)
mybatis-generator是一款在使用mybatis框架时,自动生成model,dao和mapper的工具,很大程度上减少了业务开发人员的手动编码时间 坐着在idea上用maven构建spri ...
- 直接在x86硬件上显示图片(无os)
1 任务 为了学习计算机底层和os,我给自己布置了一个任务:在x86硬件上,使用c和nasm来显示一张bmp图片.完成这个任务,前后估计花了2个月的业余时间. 这个任务涉及了很多知识点,包括:启动区. ...
- tensorflow对鸢尾花进行分类——人工智能入门篇
tensorflow之对鸢尾花进行分类 任务目标 对鸢尾花数据集分析 建立鸢尾花的模型 利用模型预测鸢尾花的类别 环境搭建 pycharm编辑器搭建python3.* 第三方库 tensorflow1 ...
- Spring Boot使用AOP的正确姿势
一.为什么需要面向切面编程? 面向对象编程(OOP)的好处是显而易见的,缺点也同样明显.当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录.性能监控等,如果采用面向对象编程的方法, ...
- Flutter日常笔记
factory修饰的构造方法 表示不是每次返回的都是新创建出来的对象, 可以取内存中已有的, 比如单例模式的书写 每次返回的都是一个实例, 这时要使用factory修饰构造方法 flutter不要求显 ...
- $0.\dot{9}=1,是指以1为极限,而非初等数学的相等“=”$
$注:文中的讨论,没有使用严格的 \epsilon 极限定义,而是简单假设$ 按照中小学的定义,整数,有限小数,无限循环小数是有理数.无限不循环小数是无理数. $\frac{1}{3}=0.\dot{ ...
- R常用统计 - 相关关系分析
数据格式 每行分别为表型和基因表达情况对应标量,每列分别为样品名的矩阵.假定前9列为phenotype,从第10行起为gene_id,编写简单for循环如下: script require(" ...
- 进度条函数 -------ajax初试
做一个显示任务完成情况的进度条: <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...
- 如何在 UltraEdit 删除空行(含空格,制表符)
如何在 UltraEdit 删除空行(含空格,制表符) 打开UltraEdit,ctrl+r弹出替换对话框,点选启用正则表达式方法1:在查找框输入 ^p^p:在替换框输入 ^p执行全部替换:这种方法是 ...