AVL树
简介
在查找章节中提到了集合,集合分为动态集合与静态集合,顺势引出顺序查找与快表的概念。有了排序与快表,二分查找算法油然而生,进一步的衍生出融合了二分查找与顺序查找的分块查找。但是考虑到动态集合的频繁插入与删除操作,人们想出了二分查找树(BST)。可是BST的最坏情况令人无法接受,三位学者提出一种算法将BST结构限制为完全二叉树(AVL),这样频繁插入与删除时的效率大大提升。
AVL
逻辑
- BST的插入与删除
- 通过旋转保证完全二叉树结构
实现
#include <iostream>
#define SOURCE_ADDRESS "C:\\Users\\***\\Desktop\\AVLTreeInput.txt"
using namespace std;
struct Node {
int data;
Node *left, *right;
int height;
};
Node* newNode(int data) {
Node* node = new Node();
node->data = data;
node->left = NULL;
node->right = NULL;
node->height = 1;
return node;
}
int getHeight(Node* node) {
return node ? node->height : 0;
}
int getBalance(Node* node) {
return node ? getHeight(node->left) - getHeight(node->right) : 0;
}
Node* leftRotate(Node* x) {
Node* y = x->right;
Node* z = y->left;
x->right = z;
y->left = x;
x->height = 1 + max(getHeight(x->left), getHeight(x->right));
y->height = 1 + max(getHeight(y->left), getHeight(y->right));
return y;
}
Node* rightRotate(Node* x) {
Node* y = x->left;
Node* z = y->right;
x->left = z;
y->right = x;
x->height = 1 + max(getHeight(x->left), getHeight(x->right));
y->height = 1 + max(getHeight(y->left), getHeight(y->right));
return y;
}
Node* insert(Node* node, int data) {
if (!node) return newNode(data);
if (data < node->data) node->left = insert(node->left, data);
else if (data > node->data) node->right = insert(node->right, data);
else return node;
node->height = 1 + max(getHeight(node->left), getHeight(node->right));
int balance = getBalance(node);
// LL
if (balance > 1 && data < node->left->data) return rightRotate(node);
// LR
if (balance > 1 && data > node->left->data) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// RR
if (balance < -1 && data > node->right->data) return leftRotate(node);
// RL
if (balance < -1 && data < node->right->data) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
return node;
}
Node* minValueNode(Node* node) {
Node* current = node;
while (current && current->left) current = current->left;
return current;
}
Node* deleteNode(Node* root, int data) {
if (!root) return root;
// 执行正常的 BST 删除
if (data < root->data) {
root->left = deleteNode(root->left, data);
} else if (data > root->data) {
root->right = deleteNode(root->right, data);
} else {
// 节点只有一个子节点或没有子节点
if (!root->left) {
Node* temp = root->right;
delete root; // 释放当前节点的内存
return temp; // 返回右子节点
} else if (!root->right) {
Node* temp = root->left;
delete root; // 释放当前节点的内存
return temp; // 返回左子节点
}
// 节点有两个子节点,获取中序后继(最小节点)
Node* temp = minValueNode(root->right);
root->data = temp->data; // 替换数据
root->right = deleteNode(root->right, temp->data); // 删除后继节点
}
// 更新高度
root->height = 1 + max(getHeight(root->left), getHeight(root->right));
// 重新平衡树
int balance = getBalance(root);
// LL
if (balance > 1 && getBalance(root->left) >= 0) return rightRotate(root);
// LR
if (balance > 1 && getBalance(root->left) < 0) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
// RR
if (balance < -1 && getBalance(root->right) <= 0) return leftRotate(root);
// RL
if (balance < -1 && getBalance(root->right) > 0) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
int sumNode = 0, sumSuc = 0;
int treeHeight = 0;
void preOrderCountNodes(Node* node, int depth) {
if (!node) return;
// cout << node->data << " ";
sumNode++;
sumSuc += depth;
preOrderCountNodes(node->left, depth+1);
preOrderCountNodes(node->right, depth+1);
}
void output(){
cout << "树高为:" << treeHeight << endl;
cout << "共" << sumNode << "个顶点" << endl;
printf("AVL=%3.2f\n", sumSuc * 1.0 / sumNode);
}
void preOrder(Node * node){
if(!node) return;
cout << node->data << ' ';
preOrder(node->left);
preOrder(node->right);
}
int main() {
Node* root = NULL;
//file opeing
FILE * f = fopen(SOURCE_ADDRESS, "r");
if(f == NULL){
cout << "file opening error" << endl;
return 0;
}
//file operating
char c; int d;
while(fscanf(f, " %c,%d", &c, &d) == 2){
if(c == 'I'){
root = insert(root, d);
}else if (c == 'D'){
root = deleteNode(root, d);
}
printf("c = %c, d = %d\n", c, d);
}
//file closing
fclose(f);
//outputing
treeHeight = getHeight(root);
preOrderCountNodes(root, 1);
output();
return 0;
}
代码对应课程实验,文件在文件夹
Reference https://zh.wikipedia.org/wiki/AVL树

浙公网安备 33010602011771号