HolyAVLTree

This commit is contained in:
e2hang
2025-08-19 18:01:45 +08:00
parent 6a8b2b7cb7
commit 03d0c1b039
6 changed files with 407 additions and 1 deletions

View File

@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.31)
project(AVLTree)
set(CMAKE_CXX_STANDARD 20)
add_executable(AVLTree main.cpp)

Binary file not shown.

View File

@@ -1,2 +1,4 @@
# 旋转的本质不能改变BST的属性 # 旋转的本质不能改变BST的属性
左旋,是指把本节点移动到本节点右节点的左节点上; 右旋,是指把本节点移动到本节点左节点的右节点上 左旋,是指把本节点移动到本节点右节点的左节点上; 右旋,是指把本节点移动到本节点左节点的右节点上
LR的情况先把LR的左节点左旋形成LL然后再按照LL的方式处理
RL同理

View File

@@ -0,0 +1,263 @@
//
// Created by PC on 25-8-17.
//
#ifndef AVL_H
#define AVL_H
#include <iostream>
#include "TreeNode.h"
#include <iostream>
#include <deque>
template <class T>
class AVL {
private:
TreeNode<T>* root;
int totalHeight;
void insert(TreeNode<T>* &r, T element);
void erase(TreeNode<T>* &r, T element);
void inOrder(TreeNode<T>* r);
public:
//构造函数
AVL(): root(nullptr), totalHeight(0) {}
explicit AVL(TreeNode<T>* root): root(root), totalHeight(1) {}
AVL(TreeNode<T>* root, int height): root(root), totalHeight(height) {}
AVL(const AVL<T> &other) {/*深拷贝*/}
~AVL() {
dispose(root);
root = nullptr;
}
//返回
int getTotalHeight() const { return totalHeight; }
int getHeight(TreeNode<T>* node) const {
return node ? node->height : 0;
}
int getBalance(TreeNode<T>* node) const {
return getHeight(node->left) - getHeight(node->right);
}
TreeNode<T>* getRoot() { return root; }
//4种旋转关注返回值递归
TreeNode<T>* LL(TreeNode<T>* &node);
TreeNode<T>* RR(TreeNode<T>* &node);
TreeNode<T>* LR(TreeNode<T>* &node);
TreeNode<T>* RL(TreeNode<T>* &node);
//中序遍历//删除节点
void display() {
std::cout << "Root is: " << root->element << std::endl;
inOrder(root);
std::cout << std::endl;
}
void dispose(TreeNode<T>* r);
//功能
void insert(T element);
void erase(T element);
void outputTree(int n);
};
template<class T>
TreeNode<T> * AVL<T>::LL(TreeNode<T> *&node) {
TreeNode<T>* left = node->left;
TreeNode<T>* right = left->right;
node->left = right;
left->right = node;
//调整高度,已更新
node->height = std::max(getHeight(node->right), getHeight(node->left)) + 1;
left->height = std::max(getHeight(left->left), getHeight(left->right)) + 1;
return left;
}
template<class T>
TreeNode<T>* AVL<T>::RR(TreeNode<T> *&node) {
TreeNode<T>* right = node->right;
TreeNode<T>* left = right->left;
right->left = node;
node->right = left;
//调整高度
node->height = std::max(getHeight(node->right), getHeight(node->left)) + 1;
right->height = std::max(getHeight(right->left), getHeight(right->right)) +1;
return right;
}
template<class T>
TreeNode<T> * AVL<T>::LR(TreeNode<T> *&node) {
node->left = RR(node->left);
node = LL(node);
//不用再调整高度,组合技
return node;
}
template<class T>
TreeNode<T> * AVL<T>::RL(TreeNode<T> *&node) {
node->right = LL(node->right);
node = RR(node);
return node;
}
template<class T>
void AVL<T>::inOrder(TreeNode<T> *r) {
if (r != nullptr) {
inOrder(r->left);
std::cout << r->element << " ";
inOrder(r->right);
}
}
template<class T>
void AVL<T>::dispose(TreeNode<T> *r) {
if (r != nullptr) {
dispose(r->left);
dispose(r->right);
delete r;
}
}
template<class T>
void AVL<T>::insert(T element) {
insert(root, element);
}
template<class T>
void AVL<T>::erase(T element) {
erase(root, element);
}
//n是输入的max
template<class T>
void AVL<T>::outputTree(int n) {
int index = 0;
std::deque<TreeNode<T> *> q;
q.push_back(root);
while (true) {
if (q[index] != nullptr && q[index]->element == n) {break;}
if (q[index]->left) q.push_back(q[index]->left);
if (q[index]->right) q.push_back(q[index]->right);
index++;
}
int cnt = 1;
int jmp = 1;
for (int i = 0; i <= index; i++) {
cnt--;
q[i] != nullptr ? std::cout << q[i]->element << " " : std::cout << "-1" << " ";
if (cnt == 0) {
jmp *= 2;
cnt = jmp;
std::cout << std::endl;
}
}
std::cout << std::endl;
}
template<class T>
void AVL<T>::insert(TreeNode<T>* &r, T element) {
//BST插入
if (r == nullptr) {
r = new TreeNode<T>(element);
return ;
}
if (element < r->element) {
insert(r->left, element);
}
else if (element > r->element) {
insert(r->right, element);
}
//更新高度注意在回溯的时候已经更新了每个父节点的height不需要再调整中序遍历一遍
r->height = std::max(getHeight(r->left), getHeight(r->right)) + 1;
//旋转-关注四个条件
int balance = getBalance(r);
if (balance > 1 && element < r->left->element) {
//LL
r = LL(r);
}
else if (balance < -1 && element > r->right->element) {
//RR
r = RR(r);
}
else if (balance > 1 && element > r->left->element) {
//LR
r->left = RR(r->left);
r = LL(r);
}
else if (balance < -1 && element < r->right->element) {
//RL
r->right = LL(r->right);
r = RR(r);
}
}
template<class T>
void AVL<T>::erase(TreeNode<T> *&r, T element) {
/*
先按照二叉搜索树的规则删除节点:若删除节点没有孩子 → 直接删除 。
若只有一个孩子 → 让孩子接替它 。
若有两个孩子 → 找 中序后继(右子树最小) 或 中序前驱(左子树最大),替换值,再递归删除.
*/
if (r == nullptr) {
return;
}
TreeNode<T> *tmp = r;
if (element < r->element) {
erase(r->left, element);
}
else if (element > r->element) {
erase(r->right, element);
}
else {
//p = 0 or 1
if (r->left == nullptr || r->right == nullptr) {
tmp = r->left ? r->left : r->right;
if (!tmp) {
tmp = r;
r = nullptr;
}
else {
*r = *tmp;
}
delete tmp;
}
//p = 2
else if (r->left != nullptr && r->right != nullptr) {
//right-min或left-max提到最上
TreeNode<T> *min = r->right;
while (min->left != nullptr) {
min = min->left;
}
r->element = min->element;
erase(r->right, min->element);
}
}
if (!r) return;
//这里再对每个节点进行操作,旋转;回溯的时候会将父/祖父节点都旋转
//更新高度
r->height = std::max(getHeight(r->left), getHeight(r->right)) + 1;
//检查左右孩子
int balance = getBalance(r);
//关注和insert的区别
if (balance > 1 && getBalance(r->left) >= 0) {
//LL
r = LL(r);
}
else if (balance < -1 && getBalance(r->right) <= 0) {
//RR
r = RR(r);
}
else if (balance > 1 && getBalance(r->left) < 0) {
//LR
r->left = RR(r->left);
r = LL(r);
}
else if (balance < -1 && getBalance(r->right) > 0) {
//RL
r->right = LL(r->right);
r = RR(r);
}
}
#endif //AVL_H

View File

@@ -0,0 +1,97 @@
#include <iostream>
#include "avl.h"
using namespace std;
int main() {
AVL<int> tree;
tree.insert(10);
tree.display();
tree.outputTree(10);
tree.insert(20);
tree.display();
tree.outputTree(20);
tree.insert(30);
tree.display();
tree.outputTree(30);
tree.insert(100);
tree.display();
tree.outputTree(100);
tree.insert(50);
tree.display();
tree.outputTree(50);
tree.insert(70);
tree.display();
tree.outputTree(70);
tree.insert(80);
tree.display();
tree.outputTree(80);
tree.insert(60);
tree.display();
tree.outputTree(60);
cout << endl << endl << endl;
cout << "To erase: " << endl;
tree.erase(60);
tree.display();
tree.outputTree(100);
tree.erase(100);
tree.display();
tree.outputTree(80);
return 0;
}
/*
OutputTree写的不好
Root is: 10
10
10
Root is: 10
10 20
10
20
Root is: 20
10 20 30
20
10 30
Root is: 20
10 20 30 100
20
10 30
100
Root is: 20
10 20 30 50 100
20
10 50
Root is: 50
10 20 30 50 70 100
50
20 100
10 30 70
Root is: 50
10 20 30 50 70 80 100
50
20 80
Root is: 50
10 20 30 50 60 70 80 100
50
20 80
10 30 70 100
60
To erase:
Root is: 50
10 20 30 50 70 80 100
50
20 80
10 30 70 100
Root is: 50
10 20 30 50 70 80
50
20 80
*/

View File

@@ -0,0 +1,38 @@
//
// Created by PC on 25-8-17.
//
#ifndef TREENODE_H
#define TREENODE_H
template<class T>
class TreeNode {
public:
T element;
TreeNode<T>* left;
TreeNode<T>* right;
int height;
TreeNode(): left(nullptr), right(nullptr), height(0) {}
explicit TreeNode(T e): element(e), left(nullptr), right(nullptr), height(1) {}
TreeNode(T e, TreeNode<T>* l, TreeNode<T>* r): element(e), left(l), right(r), height(1) {}
};
#endif //TREENODE_H
/*
30
/ \
25 35
/ \
20 32
/
5
旋转之后应该是:
1
/ \
r 4
/ \
3 2
/
5
*/