diff --git a/BinaryTree/BalanceTree/AVLTree/CMakeLists.txt b/BinaryTree/BalanceTree/AVLTree/CMakeLists.txt new file mode 100644 index 0000000..4c4cf25 --- /dev/null +++ b/BinaryTree/BalanceTree/AVLTree/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.31) +project(AVLTree) + +set(CMAKE_CXX_STANDARD 20) + +add_executable(AVLTree main.cpp) diff --git a/BinaryTree/BalanceTree/AVLTree/OutputLogic.pdf b/BinaryTree/BalanceTree/AVLTree/OutputLogic.pdf new file mode 100644 index 0000000..ddebd3e Binary files /dev/null and b/BinaryTree/BalanceTree/AVLTree/OutputLogic.pdf differ diff --git a/BinaryTree/BalanceTree/AVLTree/README.MD b/BinaryTree/BalanceTree/AVLTree/README.MD index c4ffbcb..bccecfd 100644 --- a/BinaryTree/BalanceTree/AVLTree/README.MD +++ b/BinaryTree/BalanceTree/AVLTree/README.MD @@ -1,2 +1,4 @@ # 旋转的本质:不能改变BST的属性 -左旋,是指把本节点移动到本节点右节点的左节点上; 右旋,是指把本节点移动到本节点左节点的右节点上 \ No newline at end of file +左旋,是指把本节点移动到本节点右节点的左节点上; 右旋,是指把本节点移动到本节点左节点的右节点上 +LR的情况:先把LR的左节点左旋,形成LL,然后再按照LL的方式处理 +RL同理 \ No newline at end of file diff --git a/BinaryTree/BalanceTree/AVLTree/avl.h b/BinaryTree/BalanceTree/AVLTree/avl.h new file mode 100644 index 0000000..6d81683 --- /dev/null +++ b/BinaryTree/BalanceTree/AVLTree/avl.h @@ -0,0 +1,263 @@ +// +// Created by PC on 25-8-17. +// + +#ifndef AVL_H +#define AVL_H +#include + +#include "TreeNode.h" +#include +#include +template +class AVL { +private: + TreeNode* root; + int totalHeight; + + void insert(TreeNode* &r, T element); + void erase(TreeNode* &r, T element); + void inOrder(TreeNode* r); + +public: + //构造函数 + AVL(): root(nullptr), totalHeight(0) {} + explicit AVL(TreeNode* root): root(root), totalHeight(1) {} + AVL(TreeNode* root, int height): root(root), totalHeight(height) {} + AVL(const AVL &other) {/*深拷贝*/} + ~AVL() { + dispose(root); + root = nullptr; + } + //返回 + int getTotalHeight() const { return totalHeight; } + int getHeight(TreeNode* node) const { + return node ? node->height : 0; + } + int getBalance(TreeNode* node) const { + return getHeight(node->left) - getHeight(node->right); + } + TreeNode* getRoot() { return root; } + + //4种旋转,关注返回值(递归) + TreeNode* LL(TreeNode* &node); + TreeNode* RR(TreeNode* &node); + TreeNode* LR(TreeNode* &node); + TreeNode* RL(TreeNode* &node); + + //中序遍历//删除节点 + void display() { + std::cout << "Root is: " << root->element << std::endl; + inOrder(root); + std::cout << std::endl; + } + void dispose(TreeNode* r); + + //功能 + void insert(T element); + void erase(T element); + void outputTree(int n); +}; + +template +TreeNode * AVL::LL(TreeNode *&node) { + TreeNode* left = node->left; + TreeNode* 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 +TreeNode* AVL::RR(TreeNode *&node) { + TreeNode* right = node->right; + TreeNode* 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 +TreeNode * AVL::LR(TreeNode *&node) { + node->left = RR(node->left); + node = LL(node); + //不用再调整高度,组合技 + return node; +} + +template +TreeNode * AVL::RL(TreeNode *&node) { + node->right = LL(node->right); + node = RR(node); + return node; +} + +template +void AVL::inOrder(TreeNode *r) { + if (r != nullptr) { + inOrder(r->left); + std::cout << r->element << " "; + inOrder(r->right); + } +} + +template +void AVL::dispose(TreeNode *r) { + if (r != nullptr) { + dispose(r->left); + dispose(r->right); + delete r; + } +} + +template +void AVL::insert(T element) { + insert(root, element); +} + +template +void AVL::erase(T element) { + erase(root, element); +} + +//n是输入的max +template +void AVL::outputTree(int n) { + int index = 0; + std::deque *> 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 +void AVL::insert(TreeNode* &r, T element) { + //BST插入 + if (r == nullptr) { + r = new TreeNode(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 +void AVL::erase(TreeNode *&r, T element) { + /* + 先按照二叉搜索树的规则删除节点:若删除节点没有孩子 → 直接删除 。 + 若只有一个孩子 → 让孩子接替它 。 + 若有两个孩子 → 找 中序后继(右子树最小) 或 中序前驱(左子树最大),替换值,再递归删除. + */ + if (r == nullptr) { + return; + } + TreeNode *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 *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 diff --git a/BinaryTree/BalanceTree/AVLTree/main.cpp b/BinaryTree/BalanceTree/AVLTree/main.cpp new file mode 100644 index 0000000..55239ae --- /dev/null +++ b/BinaryTree/BalanceTree/AVLTree/main.cpp @@ -0,0 +1,97 @@ +#include +#include "avl.h" +using namespace std; +int main() { + AVL 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 +*/ \ No newline at end of file diff --git a/BinaryTree/BalanceTree/AVLTree/treenode.h b/BinaryTree/BalanceTree/AVLTree/treenode.h new file mode 100644 index 0000000..d1a8384 --- /dev/null +++ b/BinaryTree/BalanceTree/AVLTree/treenode.h @@ -0,0 +1,38 @@ +// +// Created by PC on 25-8-17. +// + +#ifndef TREENODE_H +#define TREENODE_H +template +class TreeNode { +public: + T element; + TreeNode* left; + TreeNode* 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* l, TreeNode* r): element(e), left(l), right(r), height(1) {} +}; + +#endif //TREENODE_H +/* + 30 + / \ + 25 35 + / \ + 20 32 + / + 5 + + 旋转之后应该是: + 1 + / \ + r 4 + / \ + 3 2 +/ +5 +*/ \ No newline at end of file