平衡二叉树的左右子树的高度差小于等于1。或者说其左子树的高度减去右子树的高度,差值的绝对值小于等于1。平衡二叉树,仍然属于排序二叉树。其中序排列里,节点的关键字仍然按递增有序排列。
为了纪念对平衡二叉树的研究做出贡献的前苏联科学家,取其姓氏里的字母,平衡二叉树,也叫做AVL树。
每往AVL树里插入一个节点,由函数insertBST完成插入。都要对树里节点进行校平。
校平由函数checkBalance 完成,计算树里每个节点的平衡因子。可由后序递归完成(按节点左右根的顺序,依次校平每个节点的平衡因子)。
校平时,若发现某个节点处出现了不平衡,就相当于找到了以该节点为根的最小不平衡子树,对其进行恢复平衡操作,由函数recoverBalance完成。恢复后,最小不平衡子树外的节点不用再校平了(当然递归无法在此时停止)。因为通过对LL、RR、LR、RL的校平过程可以总结出:校平后,原最小不平衡子树的高度并没有因为新节点的插入而发生改变。所以该子树对子树外节点的平衡因子不构成影响。
因为每插入一个节点,都进行校平,所以树里的最小不平衡子树最多只有一个。
校平依据的原理:校平时,并不改变最小不平衡子树的中序遍历序列,因为树的平衡与否,其仍然属于排序树。若校平后树的中序遍历序列发生了改变,一定是校平出错了。从而,我们可以得出一个校平方案:依据中序遍历序列里节点的位置,判断哪些节点的指向关系需要改变。而不再区分什么左旋转,右旋转这些不直观的概念。此算法也受到了BST删除节点的算法启发。两者思路是一样的。理解前者的程序组织过程,有利于此处校平的思路掌握。前者同样见懒猫老师的精彩讲解。
补充一点:函数int checkBalance(Node*& root) :其返回值是以形参节点为根的树的高度。因为校平时,根节点平衡因子的取值与其左右子树的高度有关。这也是平衡因子的定义。所以,有必要计算所有节点的高度(此高度值以叶节点的高度为1,根节点高度是树里最大的)。
感谢bilibili懒猫老师的精彩讲解:懒猫老师-数据结构-(59)平衡二叉树【互动视频】_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1kT4y1w7Cx
本程序是在BST树的程序基础上加工完善而来的,程序的其ta介绍见
https://blog.csdn.net/zhangzhangkeji/article/details/119706654
完整代码如下,先是main函数所在源文件:
#include<iostream>
using namespace std;
struct Node {
int balanceFactor;
int data;
Node* ptLeftChild;
Node* ptRightChild;
};
extern void insertBST(Node * & root,int data);
extern void inOrderTraverse(Node*& root);
extern void displayBST(Node*& root);
extern bool deleteKey(Node*& root,int key);
extern void deletePt(Node *& ptDelete);
extern int checkBalance(Node*& root);
extern void recoverBalance(Node * & root);
int main() {
int a[] = {4,9,0,1,8,6,3,5,2,7},length = 10;
Node* root = NULL;
for (int i = 0; i < length; i++) {
insertBST(root, a[i]);
checkBalance(root);
}
cout << "middle order traverse : ";
inOrderTraverse(root);
cout<<endl<<"逗号表达式表示该 AVL 树 :";
displayBST(root);
cout<<endl << "delete 8 : ";
deleteKey(root,8);
checkBalance(root);
displayBST(root);
cout << endl << "delete 2 : ";
deleteKey(root, 2);
checkBalance(root);
displayBST(root);
return 0;
}
接着是各函数所在源文件:
#include<iostream>
using namespace std;
struct Node {
int balanceFactor;
int data;
Node* ptLeftChild;
Node* ptRightChild;
};
void insertBST(Node*& root, int data) {
if (root == NULL) {
root = new Node;
root->balanceFactor = 0;
root->data = data;
root->ptLeftChild = root->ptRightChild = NULL;
return;
}
if (root->data > data)
insertBST(root->ptLeftChild, data);
else if (root->data < data)
insertBST(root->ptRightChild,data);
else
cout << "key " <<data<<" repeated ! " << endl;
}
void inOrderTraverse(Node*& root) {
if (root == NULL)
return;
inOrderTraverse(root->ptLeftChild);
cout << root->data << ' ';
inOrderTraverse(root->ptRightChild);
}
void displayBST(Node*& root) {
if (root == NULL)
return;
cout << root->data;
if (root->ptLeftChild != NULL || root->ptRightChild != NULL) {
cout << '(';
displayBST(root->ptLeftChild);
if (root->ptRightChild != NULL) {
cout << ',';
displayBST(root->ptRightChild);
}
cout << ')';
}
}
bool deleteKey(Node*& root, int key) {
void deletePt(Node * &ptDelete);
if (root == NULL)
return false;
if (root->data > key)
return deleteKey(root->ptLeftChild, key);
else if (root->data < key)
return deleteKey(root->ptRightChild, key);
else
deletePt(root);
return true;
}
void deletePt(Node* & ptDelete) {
Node* ptTemp;
if (ptDelete->ptLeftChild == NULL && ptDelete->ptRightChild == NULL) {
ptTemp = ptDelete;
ptDelete = NULL;
delete ptTemp;
}
else if (ptDelete->ptLeftChild == NULL) {
ptTemp = ptDelete;
ptDelete = ptDelete->ptRightChild;
delete ptTemp;
}
else if (ptDelete->ptRightChild == NULL) {
ptTemp = ptDelete;
ptDelete = ptDelete->ptLeftChild;
delete ptTemp;
}
else {
Node* ptParentTemp = ptDelete;
ptTemp = ptDelete->ptLeftChild;
while (ptTemp->ptRightChild != NULL) {
ptParentTemp = ptTemp;
ptTemp = ptTemp->ptRightChild;
}
//情况1 : root = ptDelete = ptParentTemp , ptTemp = root.ptLeftChild
//情况2 : root = ptDelete != ptParentTemp , ptTemp = ptParentTemp.ptLeftChild
//情况3 : root != ptDelete = ptParentTemp , ptTemp = ptDelete.ptLeftChild
//情况4 : root != ptDelete != ptParentTemp , ptTemp = ptParentTemp.ptLeftChild
ptDelete->data = ptTemp->data;
if (ptParentTemp == ptDelete) //左子树的最大节点是否是左子树的根节点
ptDelete->ptLeftChild = ptTemp->ptLeftChild;
else
ptParentTemp->ptRightChild = ptTemp->ptLeftChild;
delete ptTemp;
}
}
void recoverBalance(Node*& root) {
Node* ptTemp;
if (root->balanceFactor == 2 && root->ptLeftChild->balanceFactor == 1) {
ptTemp = root->ptLeftChild;
root->ptLeftChild = ptTemp->ptRightChild;
ptTemp->ptRightChild = root;
root = ptTemp;
}
else if (root->balanceFactor == 2 && root->ptLeftChild->balanceFactor == -1) {
ptTemp = root->ptLeftChild->ptRightChild;
root->ptLeftChild->ptRightChild = ptTemp->ptLeftChild;
ptTemp->ptLeftChild = root->ptLeftChild;
root->ptLeftChild = ptTemp->ptRightChild;
ptTemp->ptRightChild = root;
root = ptTemp;
}
else if (root->balanceFactor == -2 && root->ptRightChild->balanceFactor == -1) {
ptTemp = root->ptRightChild;
root->ptRightChild = ptTemp->ptLeftChild;
ptTemp->ptLeftChild = root ;
root = ptTemp;
}
else if (root->balanceFactor == -2 && root->ptRightChild->balanceFactor == 1) {
ptTemp = root->ptRightChild->ptLeftChild;
root->ptRightChild->ptLeftChild = ptTemp->ptRightChild;
ptTemp->ptRightChild = root->ptRightChild;
root->ptRightChild = ptTemp->ptLeftChild;
ptTemp->ptLeftChild = root;
root = ptTemp;
}
}
int checkBalance(Node*& root) {
if (root == NULL)
return 0;
int heightLeft, heightRight;
heightLeft = checkBalance(root->ptLeftChild);
heightRight = checkBalance(root->ptRightChild);
root->balanceFactor = heightLeft - heightRight;
if (root->balanceFactor == 2 || root->balanceFactor == -2) {
recoverBalance(root);
return (heightLeft > heightRight) ? heightLeft : heightRight ;
}
else
return (heightLeft > heightRight) ? heightLeft + 1 : heightRight + 1;
}
测试结果与课本答案与对应的图如下:
谢谢阅读。