/******************************
备忘关键词:
平衡因子(BF)、树重(树高)
LL(左旋)、RR(右旋)
LR(先左旋后右旋)、RL(先右旋后左旋)
******************************/
#include<iostream>
#include<queue>
using namespace std;
#define max(a, b) (a > b) ? a : b
typedef struct node{
int value;
int weight;//等于左右子树中最大的树重 + 1
struct node *left;
struct node *right;
}BTNode;
int getWeight(BTNode *N) {//获得当前节点的树重
if (N == NULL) return 0;//空是零
return N->weight;
}
int getBalance(BTNode *N) {//计算当前节点的平衡因子(左 - 右)
if (N == NULL) return 0;
return getWeight(N->left) - getWeight(N->right);
}
BTNode *get_r_MinValue(BTNode *root) {//获得右子树的最小值,返回指针
BTNode *T = root;
while (T->left != NULL) T = T->left;//向左遍历直到为空
return T;
}
BTNode *lRotate(BTNode *N) {
BTNode *T = N->right;
N->right = T->left;
T->left = N;
N->weight = max(getWeight(N->left), getWeight(N->right)) + 1;
T->weight = max(getWeight(T->left), getWeight(T->right)) + 1;
return T;
}
BTNode *rRotate(BTNode *N) {
BTNode *T = N->left;
N->left = T->right;
T->right = N;
N->weight = max(getWeight(N->left), getWeight(N->right)) + 1;
T->weight = max(getWeight(T->left), getWeight(T->right)) + 1;
return T;
}
BTNode *lrRotate(BTNode *N) {
BTNode *T = N->left;
N->left = lRotate(T);
return rRotate(N);
}
BTNode *rlRotate(BTNode *N) {
BTNode *T = N->right;
N->right = rRotate(T);
return lRotate(N);
}
BTNode *toBalance_in(BTNode *root, int value) {//插入后自平衡
root->weight = max(getWeight(root->left), getWeight(root->right)) + 1;
int balance = getBalance(root);
if (balance < -1 && value > root->right->value) {//左自旋
return lRotate(root);
}
if (balance > 1 && value < root->left->value) {//右自旋
return rRotate(root);
}
if (balance < -1 && value < root->right->value) {//右旋后左旋
return rlRotate(root);
}
if (balance > 1 && value > root->left->value) {//左旋后右旋
return lrRotate(root);
}
return root;
}
BTNode *toBalance_de(BTNode *root) {//删除后自平衡
root->weight = max(getWeight(root->left), getWeight(root->right)) + 1;
int balance = getBalance(root);
//多多画图有助理解
if (balance < -1 && getBalance(root->right) == 0) {//左自旋
return lRotate(root);
//如果当前节点平衡因子 < -1且右节点平衡因子 == 0 左旋即可
}
if (balance > 1 && getBalance(root->left) == 0) {//右自旋
return rRotate(root);
//如果当前节点平衡因子 > 1且左节点平衡因子 == 0 右旋即可
}
if (balance < -1 && getBalance(root->right) > 0) {//右旋后左旋
return rlRotate(root);
}
if (balance > 1 && getBalance(root->left) < 0) {//左旋后右旋
return lrRotate(root);
}
return root;
}
BTNode *insert(BTNode *root,int value) {//平衡二叉树插入节点
if (root == NULL) { //一直遍历到空节点
BTNode *newNode = (BTNode *)malloc(sizeof(struct node));
newNode->left = NULL;
newNode->right = NULL;
newNode->value = value;
newNode->weight = 1;//新节点默认树重是1
return newNode;
}
if (value > root->value) {//插到右子树
root->right = insert(root->right, value);
}
else if (value < root->value) {//插到左子树
root->left = insert(root->left, value);
}
else return root;//重复的不存放
root = toBalance_in(root, value); //插入调整
return root;
}
BTNode *Delete(BTNode *root, int value) {
//空节点说明不存在要删除
if (root == NULL) return root;
if (root->value < value) {//如果比它小说明在右子树上
root->right = Delete(root->right, value);
}
else if (root->value > value) {//如果比它大说明在左子树上
root->left = Delete(root->left, value);
}
else {//相等就看看是哪一种情况
//分情况删除
if (root->left == NULL || root->right == NULL) {//左右子树至少有一个空
BTNode *T = (root->left == NULL) ? root->right : root->left;
if (T == NULL) {//都是空叶子节点直接删除
T = root;
root = NULL;
}
else *root = *T;
//!直接用 *T 替换 *root,而不是root = T (因为这只是指针指向,free之后会丢失节点)
free(T);
}
else {
//左右子树都不为空 就用当前节点右子树的最小值节点替换当前节点,并把最小节点删掉(尽量减少因删除而造成的旋转操作)
BTNode *T = get_r_MinValue(root->right);
root->value = T->value;
root->right = Delete(root->right, root->value);//删掉最小节点
}
}
if (root == NULL) return root;//上面的Delete可能会造成空
root = toBalance_de(root);//删除调整
return root;
}
void bfs(BTNode *root) {//层序遍历
if (root == NULL) return;
queue<BTNode*> q;
BTNode *N;
q.push(root);
while (!q.empty()) {
N = q.front();
cout << N->value << ' ';
q.pop();
if (N->left != NULL) q.push(N->left);
if (N->right != NULL) q.push(N->right);
}
}
int main() {
BTNode *root = NULL;
int num;
for (int i = 0; i < 10; i++) {//节点数为10的平衡二叉树(AVL树)
cin >> num;
root = insert(root, num);
}
cout << "初始状态层序遍历:";
bfs(root);
cout << '\n';
while(cin>>num){
root = Delete(root, num);
cout << "删除节点 " << num << " 后层序遍历:";
bfs(root);
cout << '\n';
}
return 0;
}
学习博客。
关于平衡二叉树最需要搞懂的就是它的平衡模式:LL、RR、LR、RL四种。这四种模式有的人根据插入删除的位置来理解,有的则根据旋转方向来理解,重要的是明白其运作过程,多画图往往事半功倍,有助于理解吸收。注释写的还算详细,自己动手敲敲也算大致理解了平衡二叉树。
自己试了试暂时没有发现错误,如果有误希望能够不吝指正。