二叉排序树,又称二叉查找树(BST,Binary Search Tree)
一棵二叉树或者是空二叉树,或者是具有如下性质的二叉树:
若树非空,目标值与根结点的值比较;
4. 若相等,则查找成功;
5. 若小于根结点,则在左子树上查找;
6. 否则在右子树上查找;
查找成功,返回结点指针;查找失败返回NULL 。
typedef struct BSTNode{
int key;
struct BSTNode *lchild, *rchild;
}BSTNode, *BSTree;
//在二叉排序树中查找值为key的结点(非递归)
//最坏空间复杂度:O(1)
BSTNode *BST_Search(BSTree T, int key){
while(T!=NULL && key!=T->key){ //若树空或等于跟结点值,则结束循环
if(key<T->key) //值小于根结点值,在左子树上查找
T = T->lchild;
else //值大于根结点值,在右子树上查找
T = T->rchild;
}
return T;
}
//在二叉排序树中查找值为key的结点(递归)
//最坏空间复杂度:O(h)
BSTNode *BSTSearch(BSTree T, int key){
if(T == NULL)
return NULL;
if(Kry == T->key)
return T;
else if(key < T->key)
return BSTSearch(T->lchild, key);
else
return BSTSearch(T->rchild, key);
}
//在二叉排序树中插入关键字为k的新结点(递归)
//最坏空间复杂度:O(h)
int BST_Insert(BSTree &T, int k){
if(T==NULL){ //原树为空,新插入的结点为根结点
T = (BSTree)malloc(sizeof(BSTNode));
T->key = k;
T->lchild = T->rchild = NULL;
return 1; //插入成功
}
else if(K == T->key) //树中存在相同关键字的结点,插入失败
return 0;
else if(k < T->key)
return BST_Insert(T->lchild,k);
else
return BST_Insert(T->rchild,k);
}
依次将每个关键字插入到二叉排序树中(不同的关键字序列可能得到同款二叉排序树,也可能得到不同款二叉排序树)
//按照str[]中的关键字序列建立二叉排序树
void Crear_BST(BSTree &T, int str[], int n){
T = NULL; //初始时T为空树
int i=0;
while(i<n){
BST_Insert(T,str[i]); //依次将每个关键字插入到二叉排序树中
i++;
}
}
先搜索找到目标结点:
查找长度: 在查找运算中,需要对比关键字的次数称为查找长度,反映了查找操作时间复杂度
平衡二叉树(Balanced Binary Tree),简称平衡树(AVL树,G. M. Adelson-Velsky和E. M. Landis))——树上**任一结点的左子树和右子树的高度之差不超过1。**又称自平衡二叉查找树。平衡二叉树必定是二叉搜索树,反之则不一定。
结点的平衡因子=左子树高-右子树高。
//平衡二叉树结点
typedef struct AVLNode{
int key; //数据域
int balance; //平衡因子
struct AVLNode *lchild; *rchild;
}AVLNode, *AVLTree;
在插入操作中,只要将最小不平衡子树调整平衡,则其他祖先结点都会恢复平衡。
若树高为h,则最坏情况下,查找一个关键字最多需要对比 h 次,即查找操作的时间复杂度不可能
超过 O(h)
平衡二叉树——树上任一结点的左子树和右子树的高度之差不超过1
• 删除结点后,要保持二叉排序树的特性不变(左<中<右)
• 若删除结点导致不平衡,则需要调整平衡
①删除结点(方法同“二叉排序树”)
②一路向北找到最小不平衡子树,找不到就完结撒花
③找最小不平衡子树下,“个头”最高的儿子、孙子
④根据孙子的位置,调整平衡(LL/RR/LR/RL)
孙子在LL:儿子右单旋
• 孙子在RR:儿子左单旋
• 孙子在LR:孙子先左旋,再右旋
• 孙子在RL:孙子先右旋,再左旋
⑤如果不平衡向上传导,继续②
对最小不平衡子树的旋转可能导致树变矮,从而导致上层祖先不平衡(不平衡向上传递)
例1:
平衡二叉树删除操作时间复杂度=O( l o g 2 n log_{2}n log2n)
A,根结点度可以为1,所以错
B,最小元素可以是根节点,有一个左孩子
C,不一定是叶子结点,因为如果插入后不平衡了,可能需要旋转
D,降序序列说明左大于中大于右,最大的元素一定是最左的
先按BST插入,也就是按照大小从上到下比较,将关键字插入到叶结点,如果插入后不再平衡,需要旋转一下
红黑树(Red-Black Tree)和AVL树都是自平衡的二叉搜索树,它们在保持树的平衡性和提供高效的插入、删除和查找操作方面有相似的目标。然而,它们在实现上有一些区别:
平衡性要求:AVL树要求左右子树的高度差不超过1,而红黑树没有明确的高度差限制,它只要求满足红黑树的五个性质即可。
平衡调整操作:AVL树在插入或删除节点后,可能需要进行更多的旋转操作来保持平衡,以满足高度差限制。而红黑树的平衡调整操作相对较少,通常只需要进行颜色变换和旋转。
维护开销:由于AVL树要求更严格的平衡,它的平衡调整操作相对较多,因此在频繁的插入和删除操作时,AVL树可能需要更多的平衡调整,导致维护开销较大。而红黑树的平衡调整操作相对较少,所以在插入和删除操作频繁的情况下,红黑树通常具有更好的性能。
内存占用:AVL树通常需要额外的平衡因子来记录每个节点的高度差,因此占用的内存空间相对较大。而红黑树只需要一个额外的颜色属性来记录节点的颜色,因此在内存占用上相对更优。
与“黑高”相关的推论
1.根节点黑高为 h 的红黑树,内部结点数(关键字)至少有多少个?
回答:内部结点数最少的情况——总共h层黑结点的满树形态
结论:若根节点黑高为 h h h,内部结点数(关键字)最少有 2 h − 1 2^{h}-1 2h−1个
性质2证明: 若红黑树总高度=h,则根节点黑高 ≥ h / 2 h/2 h/2,因此内部结点数 n ≥ 2 h / 2 − 1 n ≥ 2^{h/2}-1 n≥2h/2−1,由此推出 h ≤ 2 log 2 ( n + 1 ) h ≤ 2\log_{2}(n+1) h≤2log2(n+1)
2.根节点黑高为 h h h 的红黑树,内部结点数(关键字)至多有多少个?
回答:内部结点数最多的情况——h层黑结点,每一层黑结点下面都铺满一层红结点。共 2 h 2h 2h层的满树形态
结论:若根节点黑高为h,内部结点数(关键字)最多有 2 2 h − 1 2^{2h}-1 22h−1 个
下面这些选项中,满足“红黑树”定义的是(D )
A:不红红 B:跟叶黑 C:黑路同
与 BST、AVL 相同,从根出发,左小右大,若查找到一个空叶节点,则查找失败
红黑树查找操作时间复杂度 = O( l o g 2 n log_{2}n log2n),查找效率与AVL树同等数量级
查找成功:(1+22+34+43)/ 10 =2.9
查找失败时 (45 + 5*6) / 11 = 4.55
注意:插入非根节点应该是红色。
原因:根据红黑树特性之一【任意一节点到每个叶子节点的路径都包含数量相同的黑节点】,红色在父节点(如果存在)是黑色节点时,红黑树的黑色平衡不会被破坏,所以不需要进行自平衡操作。但如果插入节点是黑色,那么插入位置所在的子树黑色节点总是多1,必须做自平衡操作。
空节点也算黑叔
1.插入根节点20,插入10,5,黑叔LL
2.插入30红叔(叔父爷,爷变新)
3.插入40黑叔RR
4.插入57红叔
5.插入新结点3的父结点是黑色,无需做任何操作
6.插入2黑叔LL
7.插入4红叔
8. 9.10插入新结点35,25,18的父结点是黑色,无需做任何操作
11.插入22,红叔(叔父爷·,爷变新)
12.插入23黑叔,LR
左旋变成LL
右旋
儿换爷,儿黑爷红
14.插入24红叔
叔父爷染色,爷变新
新结点(原爷)黑叔LR
左旋
右旋
儿换爷,23黑30红
重要考点:
①红黑树删除操作的时间复杂度 = O(log2n)
②在红黑树中删除结点的处理方式和“二叉排序树的删除”一样
③按②删除结点后,可能破坏“红黑树特性”,此时需要调整结点颜色、位置,使其再次满
足“红黑树特性”。
2-3-4树是扩展于二叉树的多叉树,二叉树是一个数据项,两个子节点,234树是最少一个数据项,最多3个数据项,最少2个子节点,最多4个子节点,也就是说2-3-4树当只有一个数据项时非叶子节点有且只有2个子节点,2个数据项时3个子节点,3个数据项时4个子节点,子节点数量可以为2,3,4,所以叫2-3-4树。
运算限制:它是平衡树,有序树,添加操作只发生在叶子节点上
1.非叶节点数据项和其子节点数量的关系:
即非叶节点的子节点数总是比它含有的数据项多1
3.与红黑树的联系
红黑树就是由234树演变出来的。(红黑树是234树的一种实现),了解了234树才能明白红黑树旋转和颜色变化的底层逻辑。
结点类型
红黑树对应关系图示
上图中没有画出具体的子结点 仅用虚线框标识了一下子结点的取值范围。
不难看出,只要将红黑树中的红结点向上一提,与父结点合并,就反推出了234树。
从根节点开始搜索,(除非查找的关键 字值就是根,)选择关键字值所在的合适范围,转向那个方向,直到找到为止。
比如对于下面这幅图,我们需要查找关键字值为64的数据项。
首先从根节点开始,根节点只有一个数据项50,没有找到,而且因为64比50大,那么转到根节点的子节点child1。60|70|80 也没有找到,而且60<64<70,所以我们还是找该节点的child1,62|64|66,我们发现其第二个数据项正好是64,于是找到了。
新的数据项一般要插在叶节点里,在树的最底层。如果插入到有子节点的节点里,那么子节点的数量就要发生变化来维持树的结构,因为在2-3-4树中节点的子节点要比数据项多1。
B树,⼜称多路平衡查找树,B树中所有结点的孩⼦个数的最⼤值称为B树的阶,通常⽤m表示。⼀棵m阶B树或为空树,或为满⾜如下特性的m叉树:
m阶B树的核⼼特性:
B树和B+树的比较
(1)m阶B树:结点中的n个关键字对应n+1棵子树;
m阶B+树:结点中的n个关键字对应n棵子树。
(2)m阶B树:根节点的关键字数n[1,m-1]。其他结点的关键字数n[[m/2]-1,m-1];
m阶B+树:根节点的关键字数n[1,m]其他结点的关键字数n[[m/2],m]。
(3)m阶B树:在B树中,各结点中包含的关键字是不重复的;
m阶B+树:在B+树中,叶结点包含全部关键字非叶结点中出现过的关键字也会出现在叶结点中。
(4)m阶B树:B树的结点中都包含了关键字对应的记录的存储地址;
m阶B+树:在B+树中,叶结点包含信息,所有非叶结点仅起索引作用,非叶结点中的每个索引项只含有对应子树的最大关键字和指向该子树的指针,不含有该关键字对应记录的存储地址。