1.二叉搜索树(BST)
二叉搜索树(Binary Search Tree),也有称之为二叉排序树、二叉查找树
1.1定义和性质
在二叉树的基础上,增加了几个规则约束:
- 如果他的左⼦树不空,则左⼦树上所有结点的值均⼩于它的根结点的值。
- 若它的右⼦树不空,则右⼦树上所有结点的值均⼤于它的根结点的值。
- 它的左、右树⼜分为二叉排序树。
1.2中序遍历结果
1 2 3 4 5 6 7 8 9
1.3二叉搜索树的优势
- 二叉排序树的中序遍历,就是一个从⼩到⼤排好序的序列,但是查找时,完全没有必要先进行中序遍历生成一个有序的数组,再二分查找,直接根据二叉搜索树的约束直接操作。
- 查找时间最坏情况就是树的深度
- 二叉搜索树的查找逻辑,可以写成递归的思路和非递归思路。
BiTree SearchBST(BiTree T,KeyType key){
//如果递归过程中 T 为空,则查找结果,返回NULL;或者查找成功,返回指向该关键字的指针
if (!T || key==T->data) {
return T;
}else if(key<T->data){
//递归遍历其左孩⼦
return SearchBST(T->lchild, key);
}else{
//递归遍历其右孩⼦
return SearchBST(T->rchild, key);
}
}
1.4二叉搜索树的实现
1.4.1二叉搜索树的插入操作
- 算法思想
- 插入的新节点都是在叶节点位置
- 寻找插入节点的位置,建立父节点和新节点的左右关系
- 是一种递归思想
// 按照二分搜索树的规则插入数据(非递归方式) void insertBSTreeNoRecur(BSTree *tree, Element e){ BSNode* cur=tree->root; BSNode* pre= nullptr; //1.寻找插入新结点的位置 while(cur){ pre=cur; if(cur->data>e){ cur=cur->left; }else if(cur->data<e){ cur=cur->right; }else{ return; //存在与插入元素相同的值,直接返回 } } // 此时,pre就是唯一知道待插入节点的前一个位置在哪里 // 2. 分配节点 BSNode* node= creatBSNode(e); // 3. 将这个新的节点,放到待插入位置前面那个节点的左或右 // 放入pre指向结点的左或右 if(pre){ if(pre->data>e){ pre->left=node; }else{ pre->right=node; } }else{ //此时树中还没有节点 tree->root=node; } tree->count++; }
- 递归思路
- 涉及到前后节点,⼦问题就是返回新节点,上一个状态就是左⼦树还是右⼦树来接收
- 递归核心代码
static BSNode *insertBSNodeRecur(BSTree *tree, BSNode *node, Element e){ if(node== nullptr){ tree->count++; return creatBSNode(e); } if(node->data>e){ node->left=insertBSNodeRecur(tree,node->left,e); }else if(node->data<e){ node->right=insertBSNodeRecur(tree,node->right,e); } return node; }
1.4.2 查找某一节点下的最⼤或最⼩值
- 算法思想
- 比当前节点⼩的值,一定放在他的左⼦树上,那么一直往左查找最左边的节点,就是最⼩值
- 比当前节点⼤的值,一定放在他的右⼦树上,那么一直往右查找最左边的节点,就是最⼤值
- 核心代码
static void deleteMaxNode(BSNode* node){ BSNode *Max=node->left; //找最大值 BSNode *pre= node; while(Max&&Max->right){ pre=Max; Max=Max->right; } node->data=Max->data; //说明找到了前驱节点,可能是node节点的左孩子,也有可能是左孩子的最右边 if(pre->data==node->data){ pre->left= Max->left; }else{ pre->right= Max->left; } delete Max; }
1.4.2二叉搜索树的删除操作
- 算法分析
- 删除节点,共有三种可能性
叶子节点
- 叶⼦结点从二叉搜索树中移除后,并不影响其他结点的排列规则,直接删除
度为1的结点
- 该节点缺失左⼦树或右⼦树,当去掉这个节点后,剩余的左⼦树和右⼦树满足二叉搜索树的要求
- 矛盾在于删除的这个节点,属于父节点的左边还是右边,那么剩余的左⼦树或右⼦树仍然满足父节点的左右属性,接入这个父节点就可以
度为2的节点
- 假设要删除的节点A,他的后结点,既有⼤于他的也有⼩于他的,现在就是要选择一个节点B,满足左边节点都比B ⼩,右边节点都比B⼤。
- 其实就是中序遍历时,前一个节点或后一个节点来替换这个节点,然后删除前一个或后一个节点
先找到这个待删除结点的前一个或后一个,替换待删除结点
1234567
1234457
这个时候删除4就可以,而4一定是叶⼦结点,就⼜回到了叶⼦节点删除的逻辑
- 递归思路
- 二叉搜索树删除情况
- 删除叶⼦节点,直接删除
- 删除的节点有一个叶⼦节点,用⼦节点来替代
- 删除的节点有两个⼦节点
- 找到前驱节点,复制前驱节点的值覆盖掉预备删除的节点,然后删除前驱节点
- 找到后继节点,复制后继节点的值覆盖掉预备删除的节点,然后删除后继节点
//BSearch.h
#ifndef DATA_STRUCTURE_BSEARCHTREE_H
#define DATA_STRUCTURE_BSEARCHTREE_H
typedef int Element;
//二叉搜索树的节点,和普通二叉树没有什么区别
typedef struct bsNode{
Element data;
bsNode* left;
bsNode* right;
}BSNode;
//二叉搜索树的结构
typedef struct {
BSNode* root; //搜索树的根节点
int count; //搜索树的元素
}BSTree;
//创建BSTree的结构
BSTree* createBSTree();
// 释放BSTree及树中所有结点
void releaseBSTree(BSTree *tree);
// 中序遍历
void inOrderBSTree(BSTree *tree);
void visitBSNode(BSNode *node);
// 按照二分搜索树的规则插入数据(非递归方式)
void insertBSTreeNoRecur(BSTree *tree, Element e);
// 按照二分搜索树的规则插入数据(递归方式)
void insertBSTreeRecur(BSTree *tree, Element e);
// 在二分搜索树中,查找值为e的节点
BSNode *searchBSTree(BSTree *tree, Element e);
// 计算树的高度
int heightBSNode(BSNode *node);
// 删除二叉搜索树的某个值的节点(非递归方式)
void deleteBSTreeNoRecur(BSTree *tree, Element e);
// 删除二叉搜索树的某个值的节点(递归方式)
void deleteBSTreeRecur(BSTree *tree, Element e);
#endif //DATA_STRUCTURE_BSEARCHTREE_H
//BSearch.cpp
#include<iostream>
#include "BSearchTree.h"
//创建BSTree的结构
BSTree* createBSTree(){
BSTree *tree=new BSTree ;
tree->root= nullptr;
tree->count=0;
return tree;
}
// 后序遍历方式释放BSTree及树中所有结点
static void deleteNode(BSTree *tree,BSNode* node){
if(node){
deleteNode(tree,node->left);
deleteNode(tree,node->right);
delete node;
tree->count--;
}
}
void releaseBSTree(BSTree *tree){
if(tree){
//先释放所有书中的节点
deleteNode(tree,tree->root);
std::cout<<"还有"<<tree->count<<"个节点"<<std::endl;
//再释放树的结构
delete tree;
}
}
void visitBSNode(BSNode *node){
std::cout<<node->data<<'\t';
}
static void inOrde(BSNode* node){
if(node){
inOrde(node->left);
visitBSNode(node);
inOrde(node->right);
}
}
void inOrderBSTree(BSTree *tree){
if(tree){
inOrde(tree->root);
}
}
//创建新节点
static BSNode* createBSNode(Element e){
BSNode *node=new BSNode ;
node->data=e;
node->right=node->left= nullptr;
return node;
}
// 按照二分搜索树的规则插入数据(非递归方式)
void insertBSTreeNoRecur(BSTree *tree, Element e){
BSNode* cur=tree->root;
BSNode* pre= nullptr;
//1.寻找插入新结点的位置
while(cur){
pre=cur;
if(cur->data>e){
cur=cur->left;
}else if(cur->data<e){
cur=cur->right;
}else{
return; //存在与插入元素相同的值,直接返回
}
}
// 此时,pre就是唯一知道待插入节点的前一个位置在哪里
// 2. 分配节点
BSNode* node= createBSNode(e);
// 3. 将这个新的节点,放到待插入位置前面那个节点的左或右
// 放入pre指向结点的左或右
if(pre){
if(pre->data>e){
pre->left=node;
}else{
pre->right=node;
}
}else{ //此时树中还没有节点
tree->root=node;
}
tree->count++;
}
static BSNode *insertBSNodeRecur(BSTree *tree, BSNode *node, Element e){
if(node == nullptr){
tree->count++;
return createBSNode(e);
}
if (e < node->data) {
node->left = insertBSNodeRecur(tree, node->left, e);
} else if (e > node->data) {
node->right = insertBSNodeRecur(tree, node->right, e);
}
return node;
}
// 按照二分搜索树的规则插入数据(递归方式)
void insertBSTreeRecur(BSTree *tree, Element e){
tree->root= insertBSNodeRecur(tree,tree->root,e);
}
// 在二分搜索树中,查找值为e的节点
BSNode *searchBSTree(BSTree *tree, Element e){
if(tree){
BSNode* node=tree->root;
while(node){
if(node->data>e){
node=node->left;
}else if(node->data<e){
node=node->right;
}else if (node->data == e) {
return node;
}
}
}
return nullptr;
}
// 计算树的高度
int heightBSNode(BSNode *node){
if(node== nullptr){
return 0;
}
int leftHeight= heightBSNode(node->left);
int rightHeight= heightBSNode(node->right);
if(leftHeight>rightHeight){
return ++leftHeight;
}else{
return ++rightHeight;
}
}
static void deleteMaxNode(BSNode* node){
BSNode *Max=node->left; //找最大值
BSNode *pre= node;
while(Max&&Max->right){
pre=Max;
Max=Max->right;
}
node->data=Max->data;
//说明找到了前驱节点,可能是node节点的左孩子,也有可能是左孩子的最右边
if(pre->data==node->data){
pre->left= Max->left;
}else{
pre->right= Max->left;
}
delete Max;
}
/* 1. 找到这个待删除的节点node,还需要一个pre节点指向上一个位置
* 2. 判断node的度的情况
* */
void deleteBSTreeNoRecur(BSTree *tree, Element e){
//1.找到元素
BSNode *node=tree->root;
BSNode *pre= nullptr;
BSNode *tmp= nullptr;
while(node){
if(node->data>e){
pre=node;
node=node->left;
}else if(node->data<e){
pre=node;
node=node->right;
}else{
break;
}
}
//2.找到node,删除节点是非根节点
if(pre&&node){
//2.1判断node的度的情况
if(node->left== nullptr){ //度为0或为1
tmp=node->right;
}else if(node->right== nullptr){ //度为1
tmp=node->left;
}else{ //度为2的情况,从node节点中找前驱,然后进行删除
deleteMaxNode(node);
tree->count--;
return;
}
if(node->data<pre->data){
pre->left=tmp;
}else{
pre->right=tmp;
}
delete node;
tree->count--;
return;
}
//如果删除的是根节点
if(pre== nullptr){
deleteMaxNode(node);
tree->count--;
}
}
//找前继节点的办法
static BSNode *maxValueBSNode(BSNode *node){
while(node&&node->right){
node=node->right;
}
return node;
}
static BSNode *deleteBSNode(BSTree *tree, BSNode *node, Element e){
if(node== nullptr){
return nullptr;
}
if(e<node->data){
node->left= deleteBSNode(tree,node->left,e);
}else if(e>node->data){
node->right= deleteBSNode(tree,node->right,e);
}else{ //找到e
BSNode *tmp;
if(node->left== nullptr){
tmp=node->right;
delete node;
tree->count--;
return tmp;
}
if(node->right== nullptr){
tmp=node->left;
delete node;
tree->count--;
return tmp;
}
//度为2,删除度为2的节点,变成找到他的前继节点,将前继节点的值拷贝给度为2的点
//把删除任务,转换为删除前继节点
tmp= maxValueBSNode(node->left);
node->data=tmp->data;
node->left= deleteBSNode(tree,node->left,tmp->data);
}
return node;
}
// 删除二叉搜索树的某个值的节点(递归方式)
void deleteBSTreeRecur(BSTree *tree, Element e){
if (tree) {
tree->root = deleteBSNode(tree, tree->root, e);
}
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "BSearchTree.h"
// 1. 普通二叉搜索树测试
void test01() {
Element data[] = {55, 33, 45, 100,
22, 80, 8, 130, 120};
BSTree *tree = createBSTree();
if (tree == NULL) {
return;
}
// 插入元素
for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
//insertBSTreeNoRecur(tree, data[i]);
insertBSTreeRecur(tree, data[i]);
}
printf("二分搜索树的中序遍历:");
inOrderBSTree(tree);
printf("\n");
int h = heightBSNode(tree->root);
printf("高度: %d\n", h);
releaseBSTree(tree);
}
// 二分搜索树的测试
void binarySearchFindTest(BSTree *tree, int cnt, Element value) {
BSNode *node = NULL;
for (int i = 0; i < cnt; ++i) {
node = searchBSTree(tree, value);
if (node) {
printf("!!!BST Find!!!\n");
return;
}
}
}
// 线性查找,测试次数cnt
void linearFindTest(Element *data, int n, int cnt, Element value) {
for (int i = 0; i < cnt; ++i) {
for (int j = 0; j < n; ++j) {
if (data[j] == value) {
printf("!!! Linear Find !!!");
return;
}
}
}
}
/* 顺序表和二分搜索树的查找效率
* 随机生成n个数字,范围在1~m之间,然后测试查找m+1(找不到),模拟了最坏的情况
* 根据运行的时间,来验证线性查找和二分搜索树查找的效率
* */
void test02() {
int n = 10000;
Element m = n + 5000;
int cnt = 10000;
clock_t start, end; // 系统滴答数
// 创建n个元素,取值范围在1-m
Element *data = (Element *) malloc(sizeof(Element) * n);
srand(time(NULL));
for (int i = 0; i < n; ++i) {
data[i] = rand() % m + 1;
}
// 测试线性查找的时间
start = clock();
linearFindTest(data, n, cnt, m + 10);
end = clock();
printf("线性查找耗时: %f.\n", (double )(end - start) / CLOCKS_PER_SEC);
// 测试二分搜索树的查找时间消耗
BSTree *tree = createBSTree();
for (int i = 0; i < n; ++i) {
insertBSTreeNoRecur(tree, data[i]);
}
start = clock();
binarySearchFindTest(tree, cnt, m + 10);
end = clock();
printf("二分搜索树查找耗时: %f.\n", (double )(end - start) / CLOCKS_PER_SEC);
releaseBSTree(tree);
free(data);
}
void test03() {
Element data[] = {55, 33, 45, 100,
22, 80, 8, 130, 120};
BSTree *tree = createBSTree();
if (tree == NULL) {
return;
}
// 插入元素
for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
insertBSTreeNoRecur(tree, data[i]);
}
printf("二分搜索树的中序遍历:");
inOrderBSTree(tree);
printf("\n");
printf("删除8节点\n");
// deleteBSTreeNoRecur(tree, 55);
deleteBSTreeRecur(tree, 55);
printf("二分搜索树的中序遍历:");
inOrderBSTree(tree);
printf("\n");
releaseBSTree(tree);
}
int main() {
test01();
return 0;
}
2.二叉平衡树
AVL树是最早被发明的⾃平衡二叉查找树。在AVL树中,任一节点对应的两棵⼦树的最⼤⾼度差的绝对值为1,因 此它也被称为⾼度平衡树。AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。
查找、插入和删除在平均和最坏情况下的时间复杂度都是 O(logn)。增加和删除元素的操作则可能需要借由一次 或多次树旋转,以实现树的重新平衡。
BST 二叉树的基础上,增加左小右大的规则
AVL BST树基础上,增加每个节点的平衡因子要满足
优点:接近完全二叉树的高度,查找效率O(lognN)
缺点:插入、删除会引起大量的节点变化
红黑树:平衡 解决了AVL中插入、删除效率不高、降低了查找效率。
2.1二叉搜索树的问题
- 二叉搜索树的查找效率取决于树的⾼度,因此保持树的⾼度最⼩,即可保证树的查找效率。
- 二叉搜索树会退化成单链表,搜索效率降低为O(n)
二叉搜索树一定程度上可以提⾼搜索效率,但是当原序列有序时,例如序列 A = {1,2,3,4, 5,6},构造二叉 搜索树如图。依据此序列构造的二叉搜索树为右斜树,同时二叉树退化成单链表,搜索效率降低为 O(n)。
二叉搜索树的查找效率取决于树的⾼度,因此保持树的⾼度最⼩,即可保证树的查找效率。
2.2平衡因子
左⼦树与右⼦树的⾼度差即为该节点的平衡因⼦(BF,Balance Factor)
平衡二叉树中不存在平衡因⼦⼤于 1 的节点。
在一棵平衡二叉树中,节点的平衡因⼦只能取 0 、1 或者 -1 ,分别对应着左右⼦树等⾼,左⼦树比较⾼,右⼦树比较⾼。
2.3 平衡树失衡情况分析
2.3.1 左旋
当加入一个新节点后,右边的⾼度增加,导致失衡
2.3.2 右旋
/* 右旋操作
* py
* |
* y
* / \
* x ry
* / \
* lx rx
* */ AVLNode *rightRotate(AVLNode *y);
2.3.3 LL、RR、LR、RL
- LL :失衡节点左边⾼,新插入节点是在失衡节点左孩⼦的左边。直接对失衡节点进行右旋。
- RR:失衡节点右边⾼,新插入节点是在失衡节点右孩⼦的右边。直接对失衡节点进行左旋。
- LR:失衡节点左边⾼,新插入节点是在失衡节点左孩⼦的右边。先对左孩⼦进行左旋,再对失衡节点进行右旋。
- RL:失衡节点右边⾼,新插入节点是在失衡节点右孩⼦的左边。先对右孩⼦进行右旋,再对失衡节点进行左旋。
2.4 平衡二叉树的插入操作
- 算法思路
- 先找到要插入的节点位置,插入新节点
- 更新平衡因⼦,根据平衡因⼦⼩于-1和⼤于1的情况进行讨论
2.5平衡二叉树的删除操作
- 算法思路
- 依据二叉排序树的删除特点,依然按照3种条件进行删除,保证最后删除的都是叶⼦节点即可。
- 节点删除后,依次对节点进行平衡因⼦检查,若发现某节点不平衡,按照平衡调节法进行调节。
#ifndef AVL_TREE_H
#define AVL_TREE_H
#include <stdio.h>
#include <stdlib.h>
typedef int Element;
// 定义平衡二叉树的节点结构
typedef struct AVLNode {
Element data;
struct AVLNode *left;
struct AVLNode *right;
int height; // 每个节点的高度
}AVLNode;
// 平衡二叉树的结构
typedef struct {
AVLNode *root;
int count;
}AVLTree;
AVLTree *createAVLTree(); // 产生平衡二叉树
void releaseAVLTree(AVLTree *tree); // 释放平衡二叉树
void visitAVLNode(AVLNode *node); // 访问平衡二叉树的节点
void inOrderAVLTree(AVLTree *tree); // 平衡二叉树的中序遍历
// 插入元素到AVL树
void insertAVLTree(AVLTree *tree, Element e);
// 从AVL树中删除元素
void deleteAVLTree(AVLTree *tree, Element e);
#endif
#include "avlTree.h"
AVLTree *createAVLTree() {
AVLTree *tree = (AVLTree *) malloc(sizeof(AVLTree));
if (tree == NULL) {
fprintf(stderr, "tree malloc failed!\n");
return NULL;
}
tree->count = 0;
tree->root = NULL;
return tree;
}
static void freeNode(AVLTree *tree, AVLNode *node) {
if (node) {
freeNode(tree, node->left);
freeNode(tree, node->right);
free(node);
tree->count--;
}
}
void releaseAVLTree(AVLTree *tree) {
if (tree) {
freeNode(tree, tree->root); // 后序递归释放节点
printf("AVLTree have %d node!\n", tree->count);
free(tree);
}
}
/* 访问平衡二叉树节点,显示内容和此节点的高度 */
void visitAVLNode(AVLNode *node) {
if (node) {
printf("\t<%d:%d>", node->data, node->height);
}
}
/* 递归中序遍历 */
static void inOrderAVLNode(AVLNode *node) {
if (node) {
inOrderAVLNode(node->left);
visitAVLNode(node);
inOrderAVLNode(node->right);
}
}
void inOrderAVLTree(AVLTree *tree) {
if (tree) {
inOrderAVLNode(tree->root);
printf("\n");
}
}
static int maxNum(int a, int b) {
return (a > b) ? a : b;
}
static int h(AVLNode *node) {
if (node == NULL)
return 0;
else
return node->height;
}
/* 左旋操作
* px
* |
* x
* / \
* lx y
* / \
* ly ry
* */
static AVLNode *leftRotate(AVLNode *x) {
AVLNode *y = x->right;
x->right = y->left;
y->left = x;
// 因为是平衡树,要更新x y的高度
x->height = maxNum(h(x->left), h(x->right)) + 1;
y->height = maxNum(h(y->left), h(y->right)) + 1;
return y;
}
/* 右旋操作
* py
* |
* y
* / \
* x ry
* / \
* lx rx
* */
AVLNode *rightRotate(AVLNode *y) {
AVLNode *x = y->left;
y->left = x->right;
x->right = y;
x->height = maxNum(h(x->left), h(x->right)) + 1;
y->height = maxNum(h(y->left), h(y->right)) + 1;
return x;
}
static int getBalance(AVLNode *node) {
if (node == NULL)
return 0;
return h(node->left) - h(node->right);
}
static AVLNode *createAVLNode(Element e) {
AVLNode *node = (AVLNode *) malloc(sizeof(AVLNode));
if (node == NULL) {
return NULL;
}
node->left = node->right = NULL;
node->height = 1;
node->data = e;
return node;
}
static AVLNode *insertAVLNode(AVLTree *tree, AVLNode *node, Element e) {
if (node == NULL) { // 递归中递的边界条件
tree->count++;
return createAVLNode(e);
}
// 1. 递归找到插入 BST
if (e < node->data) {
node->left = insertAVLNode(tree, node->left, e);
} else if (e > node->data) {
node->right = insertAVLNode(tree, node->right, e);
} else { // 插入的元素,已经在AVL树中存在
return node;
}
// 2. 归的过程中,更新归中节点的高度
node->height = 1 + maxNum(h(node->left), h(node->right));
// 计算这个节点的平衡因子
int balance = getBalance(node);
// 3. 判断平衡因子 left - right > 1 L < 1 R
// 4. 调节 ,判断LL LR RR RL
if (balance > 1) { // 失衡节点的左边高度比较大 L
// 跟失衡节点的子节点判断下一步是L还是R
if (e > node->left->data) { // LR
// 把LR中 把R进行左旋,转成LL状态
node->left = leftRotate(node->left);
}
return rightRotate(node); // LL
} else if (balance < -1) { // 右边高度大了 R
if (e < node->right->data) { // L
node->right = rightRotate(node->right);
}
return leftRotate(node); // RR
}
return node; // 不需要调整,直接返回这个节点(归)
}
void insertAVLTree(AVLTree *tree, Element e) {
if (tree) {
tree->root = insertAVLNode(tree, tree->root, e);
}
}
static AVLNode *deleteAVLNode(AVLTree *tree, AVLNode *node, Element e) {
AVLNode *tmp;
if (node == NULL) { // 递到空位置,都没有进入到else
return NULL;
}
// 1. 找到要删除点,按照二分搜索树的规则,删除
if (e < node->data) {
node->left = deleteAVLNode(tree, node->left, e);
} else if (e > node->data) {
node->right = deleteAVLNode(tree, node->right, e);
} else { // 2. 找到了这个节点
if (node->left == NULL || node->right == NULL) {
tmp = node->left ? node->left : node->right;
if (tmp == NULL) { // 度为0,直接删除node,归NULL
free(node);
tree->count--;
return NULL;
} else { // 度为1,本身删除node,改为删除tmp,把tmp的关系拷贝到node上
// node->data = tmp->data;
// node->left = tmp->left;
// node->right = tmp->right;
// free(tmp);
// tree->count--;
free(node);
return tmp;
}
} else { // 找前驱节点,然后更新这个点,转为删除前驱点
tmp = node->left;
while (tmp->right) {
tmp = tmp->right;
}
node->data = tmp->data;
node->left = deleteAVLNode(tree, node->left, tmp->data);
}
}
// 2. 更新平衡因子
node->height = 1 + maxNum(h(node->left), h(node->right));
int balance = getBalance(node);
if (balance > 1) { // L
if (getBalance(node->left) < 0) { // R
node->left = leftRotate(node->left);
}
return rightRotate(node);
} else if (balance < -1) { // R
if (getBalance(node->right) > 0) { // L
node->right = rightRotate(node->right);
}
return leftRotate(node);
}
return node;
}
/* 从平衡二叉树中删除元素e
* 1. 按照二叉搜索树的规则,递归找到元素e所在节点
* 2. 判断这个节点的度
* 2.1 如果是度为1,用父节点接收存在的子树
* 2.2 如果是度为0,直接删除,父节点接收一个NULL指针
* 2.3 如果是度为2,找到这个节点的前驱或者后继节点,用这个节点的值替换度为2的点
* 转成删除前驱或者后继这个节点
* 3. 归的过程中,找失衡点
* 4. 又根据LL LR RL RR的规则,进行旋转
* */
void deleteAVLTree(AVLTree *tree, Element e) {
if (tree) {
tree->root = deleteAVLNode(tree, tree->root, e);
}
}
#include "avlTree.h"
int main() {
Element data[] = {10, 20, 30, 40,
50, 60, 67, 80};
AVLTree *tree = createAVLTree();
if (tree == NULL) {
return -1;
}
for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
insertAVLTree(tree, data[i]);
}
printf("平衡二叉树的中序遍历:");
inOrderAVLTree(tree);
printf("\n平衡二叉树的高度: %d\n", tree->root->height);
deleteAVLTree(tree, 60);
printf("平衡二叉树的中序遍历:");
inOrderAVLTree(tree);
printf("\n平衡二叉树的高度: %d\n", tree->root->height);
releaseAVLTree(tree);
return 0;
}