二叉排序树(BST),平衡二叉树(AVL)
二叉排序树(BST)
基本概念
- 也叫二叉查找树,二叉搜索树(BST:Binary Search Tree)
- 在二叉树的基础上加一个约束——顺序性:左子树<根节点<右子树(以递增为例,递减也可以,有顺序性就OK)
性质:
- 若左子树为空,则根节点小于右子树中所有节点
- 若右子树为空,则根节点大于左子树中所有节点
- 其左右子树也为二叉排序树
用途:
- 在 l o g 2 ( n + 1 ) log_{2}(n+1) log2(n+1)的次数内找到目标数据,比直接遍历节省时间。
基本操作
增加
- 二叉链表存树
- 若为空树,直接创建节点
- 若非空树,遍历找到要插入的字节点,使用pre记录父亲节点
非递归版
//插入
BSTree insert(BSTree r, int x)
{BSTNode* p = r;BSTNode* pre = NULL;//查找需要插入的位置while (p != NULL) {if (x < p->data) {pre = p;p = p->l;}else {pre = p;p = p->r;}}BSTNode* s = (BSTNode*)malloc(sizeof(BSTNode));s->data = x;s->l = s->r = NULL;if (s->data < pre->data) {pre->l = s;}else {pre->r = s;}return r;
}
递归版
- 递归出口:当碰到NULL时,即为需要插入的地方。
BSTree insert_D(BSTree r, int x)
{if (r == NULL){BSTNode* s = (BSTNode*)malloc(sizeof(BSTNode));s->data = x;s->l = s->r = NULL;return s;}if (x < r->data){r->l = insert_D(r->l, x);return r;}if (x > r->data){r->r = insert_D(r->r, x);return r;}
}
删除
- 递归找到删除节点
- 节点的度为0,直接删除,让父节点指针指向为空。
- 节点的度为1,直接让字孩子顶替,
- 节点的度为2,将中序遍历前驱或者后继节点顶替该节点,
//删除
BSTree BSTdelete(BSTree root, int x)
{if (root == NULL) {return NULL;}if (x > root->data) {root->r = BSTdelete(root->r, x);}else if (x < root->data) {root->l = BSTdelete(root->l, x);}else {if (root->l != NULL && root->r != NULL) {//度为2//用前驱节点替换BSTNode* p = root->l;while (p->r != NULL) {p = p->r;}root->data = p->data;root->l = BSTdelete(root->l, p->data);}else {BSTNode* p = root;if (root->l == NULL) {root = root->r;}else {root = root->l;}free(p);p = NULL;}}return root;
}
查找
- 遍历寻找,小了去左子树找,大了去右子树找。
非递归版
void search(BSTree root, int x)
{BSTNode* p = root;while (p != NULL && p->data != x) {if (x < p->data) {p = p->l;}else {p = p->r;}}if (p == NULL){printf("未找到\n");}else {printf("已找到\n");}
}
递归版
void search_D(BSTree root, int x)
{if (root == NULL){printf("未找到\n");}if (root->data == x){printf("已找到\n");}if (x < root->data){search_D(root->l, x);}if (x > root->data){search_D(root->r, x);}
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>typedef struct BSTnode {int data;struct BSTnode* l;struct BSTnode* r;
}BSTNode,*BSTree;BSTree initBST(int x)
{BSTNode* r = (BSTNode*)malloc(sizeof(BSTNode));if (r == NULL) {printf("内存分配成功\n");return;}r->data = x;r->l = r->r = NULL;return r;
}//插入
BSTree insert(BSTree r, int x)
{BSTNode* p = r;BSTNode* pre = NULL;while (p != NULL) {if (x < p->data) {pre = p;p = p->l;}else {pre = p;p = p->r;}}BSTNode* s = (BSTNode*)malloc(sizeof(BSTNode));s->data = x;s->l = s->r = NULL;if (s->data < pre->data) {pre->l = s;}else {pre->r = s;}return r;
}BSTree insert_D(BSTree root, int x)
{if (root == NULL){BSTNode* s = (BSTNode*)malloc(sizeof(BSTNode));s->data = x;s->l = s->r = NULL;return s;}if (x < root->data){root->l = insert_D(root->l, x);return root;}if (x > root->data){root->r = insert_D(root->r, x);return root;}
}//查找
void search(BSTree root, int x)
{BSTNode* p = root;while (p != NULL && p->data != x) {if (x < p->data) {p = p->l;}else {p = p->r;}}if (p == NULL){printf("未找到\n");}else {printf("已找到\n");}
}void search_D(BSTree root, int x)
{if (root == NULL){printf("未找到\n");}if (root->data == x){printf("已找到\n");}if (x < root->data){search_D(root->l, x);}if (x > root->data){search_D(root->r, x);}
}//输出
void inOrder(BSTree root)
{if (root == NULL) {return;}if (root->l != NULL){inOrder(root->l);}printf("%d ", root->data);if (root->r != NULL){inOrder(root->r); }
}//删除
BSTree BSTdelete(BSTree root, int x)
{if (root == NULL) {return NULL;}if (x > root->data) {root->r = BSTdelete(root->r, x);}else if (x < root->data) {root->l = BSTdelete(root->l, x);}else {if (root->l != NULL && root->r != NULL) {//度为2//用前驱节点替换BSTNode* p = root->l;while (p->r != NULL) {p = p->r;}root->data = p->data;root->l = BSTdelete(root->l, p->data);}else {BSTNode* p = root;if (root->l == NULL) {root = root->r;}else {root = root->l;}free(p);p = NULL;}}return root;
}int main()
{int n;int a[100];scanf_s("%d", &n);for (int i = 1; i <= n; i++) {scanf_s("%d", &a[i]);}BSTree root = initBST(a[1]);if (root == NULL) {printf("建树失败\n");return 0;}for (int i = 2; i <= n; i++){insert_D(root, a[i]);}inOrder(root);printf("\n");BSTdelete(root, 6);inOrder(root);return 0;
}
/*
9
8 3 10 1 6 14 4 7 13
*/
应用场景
- 可以将查找操作的次数降到 l o g ( n ) log(n) log(n)
- 当原序列有序时,构建的BST是斜树,没有降低操作次数
- 优化:使二叉树左右子树的高度差不多,看上去比较饱满,像完全二叉树,此时可以在二叉排序树上加上一个平衡因子,又称为二叉平衡树(AVL)
二叉平衡树(AVL)
精美图形化演示如何旋转:【平衡二叉树(AVL树)】
AVL的插入和删除操作图形化展示:【「六分钟速通」平衡二叉树(AVL树)的插入与删除】
基本概念
- 一个节点平衡因子:该节点左右子树的高度差<=1
- AVL树:
- 可以是空树
- 若非空,保持顺序性并且任何一个节点的左右子树高度差的绝对值不超过
- 任何一个节点的左右子树也都是AVL树
- AVL的核心精髓就在于旋转之中,弄清楚了旋转,如何插入和删除也是顺水推舟的事情了
基本操作
插入
- 先按BST的插入方式操作cur
- 判断cur节点是否失衡,没有失衡,over
- 若失衡,优先调整以x最近的长辈为孩子的失衡子树–最小失衡子树
如何调整:
- 失衡的四种情况:
-
L L 失衡节点z的左孩子y的左子树中插入节点x导致失衡。
p=x->left
x->left=p->right
p->right=x -
L R 失衡节点z的左孩子的右子树中插入节点导致失衡
先以y为根左旋,转化为LL的情况 -
R R 失衡节点z的右孩子的右子树中插入节点导致失衡
p=p->right
x->right=p->left
p->left=x; -
R L 失衡节点z的右孩子的左子树中插入节点导致失衡
先以y为根右旋,转化为RR
-
- 调整操作:
- 旋转操作,使得孩子节点变为根节点,将父节点旋转为孩子的孩子。
//LL失衡
AVLTree LL_rotation(AVLTree x)
{AVLnode* y = x->l;x->l = y->r;y->r = x;x->high = max(get_h(x->l), get_h(x->r)) + 1;y->high = max(get_h(y->l), get_h(y->r)) + 1;return y;
}//RR失衡
AVLTree RR_rotation(AVLTree x)
{AVLnode* y = x->r;x->r = y->l;y->l = x;x->high = max(get_h(x->l), get_h(x->r)) + 1;y->high = max(get_h(y->l), get_h(y->r)) + 1;return y;
}//LR失衡
AVLTree LR_rotation(AVLTree x)
{x->l = RR_rotation(x->l);x = LL_rotation(x);return x;
}//RL失衡
AVLTree RL_rotation(AVLTree x)
{x->r = LL_rotation(x->r);x = RR_rotation(x);return x;
}
查找操作
- 与二叉排序树的查找完全一致。
删除
- 删除可能导致失衡,但只会影响到与该节点有联系的父节点
//删除
AVLTree delete_AVL(AVLTree root, int k)
{if (root == NULL){return root;}if (k < root->data){root->l = delete_AVL(root->l, k);//root可能失衡if (get_h(root->r) - get_h(root->r) > 1){AVLnode* temp = root->r;if (get_h(temp->r) >= get_h(temp->l))//RR{root = RR_rotation(root);}else {//RLroot = RL_rotation(root);}}}else if (k > root->data){root->r = delete_AVL(root->r, k);//root可能失衡if (get_h(root->l) - get_h(root->r) > 1){AVLnode* temp = root->l;if (get_h(temp->l) >= get_h(temp->r))//LL{root = LL_rotation(root);}else {//LRroot = LR_rotation(root);}}}else if (root->l != NULL && root->r != NULL)//度为2的节点{AVLnode* re = find_re(root->r);root->data = re->data;root->r = delete_AVL(root->r, re->data);//root可能失衡if (get_h(root->l) - get_h(root->r) > 1){AVLnode* temp = root->l;if (get_h(temp->l) >= get_h(temp->r))//LL{root = LL_rotation(root);}else {//LRroot = LR_rotation(root);}}}else {//度为1或0的节点AVLnode* c = root;if (root->l == NULL){root = root->r;}else {root = root->l;}free(c);c = NULL;}if(root!=NULL) root->high = max(get_h(root->l), get_h(root->r)) + 1;return root;
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>//AVL节点结构
typedef struct AVLnode
{int data;struct AVLnode* l;struct AVLnode* r;int high;//节点的高度
}AVLnode,*AVLTree;//初始化
AVLTree initAVLTree(int k)
{AVLnode* root = (AVLnode*)malloc(sizeof(AVLnode));root->data = k;root->l = root->r = NULL;root->high = 1;return root;
}//得到节点高度
int get_h(AVLnode* x)
{if (x != NULL){return x->high;}else {return 0;}
}//LL失衡
AVLTree LL_rotation(AVLTree x)
{AVLnode* y = x->l;x->l = y->r;y->r = x;x->high = max(get_h(x->l), get_h(x->r)) + 1;y->high = max(get_h(y->l), get_h(y->r)) + 1;return y;
}//RR失衡
AVLTree RR_rotation(AVLTree x)
{AVLnode* y = x->r;x->r = y->l;y->l = x;x->high = max(get_h(x->l), get_h(x->r)) + 1;y->high = max(get_h(y->l), get_h(y->r)) + 1;return y;
}//LR失衡
AVLTree LR_rotation(AVLTree x)
{x->l = RR_rotation(x->l);x = LL_rotation(x);return x;
}//RL失衡
AVLTree RL_rotation(AVLTree x)
{x->r = LL_rotation(x->r);x = RR_rotation(x);return x;
}//插入
AVLTree insert_AVL(AVLTree root, int k)
{if (root == NULL){AVLnode* s = (AVLnode*)malloc(sizeof(AVLnode));s->data = k;s->l = s->r = NULL;s->high = 1;return s;}if (k < root->data){root->l = insert_AVL(root->l, k);//判断是否失衡if (get_h(root->l) - get_h(root->r) > 1){AVLnode* l = root->l;//判断失衡情况if (k < l->data){root = LL_rotation(root);}else {root = LR_rotation(root);}}}if (k > root->data){root->r = insert_AVL(root->r, k);//判断是否失衡if (get_h(root->r) - get_h(root->l) > 1){AVLnode* r = root->r;//判断失衡情况if (k > r->data){root = RR_rotation(root);}else {root = RL_rotation(root);}}}root->high = max(get_h(root->l), get_h(root->r)) + 1;return root;
}//中序遍历
void inOrder(AVLTree root)
{if (root != NULL){inOrder(root->l);printf("%d %d\n", root->data, root->high);inOrder(root->r);}
}//找后继
AVLnode* find_re(AVLnode* p)
{while (p->l != NULL){p = p->l;}return p;
}//删除
AVLTree delete_AVL(AVLTree root, int k)
{if (root == NULL){return root;}if (k < root->data){root->l = delete_AVL(root->l, k);//root可能失衡if (get_h(root->r) - get_h(root->r) > 1){AVLnode* temp = root->r;if (get_h(temp->r) >= get_h(temp->l))//RR{root = RR_rotation(root);}else {//RLroot = RL_rotation(root);}}}else if (k > root->data){root->r = delete_AVL(root->r, k);//root可能失衡if (get_h(root->l) - get_h(root->r) > 1){AVLnode* temp = root->l;if (get_h(temp->l) >= get_h(temp->r))//LL{root = LL_rotation(root);}else {//LRroot = LR_rotation(root);}}}else if (root->l != NULL && root->r != NULL)//度为2的节点{AVLnode* re = find_re(root->r);root->data = re->data;root->r = delete_AVL(root->r, re->data);//root可能失衡if (get_h(root->l) - get_h(root->r) > 1){AVLnode* temp = root->l;if (get_h(temp->l) >= get_h(temp->r))//LL{root = LL_rotation(root);}else {//LRroot = LR_rotation(root);}}}else {//度为1或0的节点AVLnode* c = root;if (root->l == NULL){root = root->r;}else {root = root->l;}free(c);c = NULL;}if(root!=NULL) root->high = max(get_h(root->l), get_h(root->r)) + 1;return root;
}int main()
{int n;int a[105];scanf_s("%d", &n);for (int i = 1; i <= n; i++){scanf_s("%d", &a[i]);}AVLTree root = initAVLTree(a[1]);for (int i = 2; i <= n; i++){root = insert_AVL(root, a[i]);}inOrder(root);int sign;scanf_s("%d", &sign);root = delete_AVL(root, sign);inOrder(root);return 0;
}
/*
8
1 2 3 4 5 6 7 8
*/