AVL樹的旋轉和插入
阿新 • • 發佈:2019-01-03
包含了AVL樹的單旋轉和雙旋轉的演算法,以及AVL樹的遞迴插入和非遞迴插入演算法。單旋轉也叫“一”字形旋轉,又可分為左-左型旋轉和右-右型旋轉;雙旋轉也叫“之”字形旋轉,又可分為左-右型旋轉和右-左型旋轉。
#include<iostream>
#include<stack>
using namespace std;
class AVLNode{
public:
int element;
AVLNode* left;
AVLNode* right;
int height;
AVLNode(int x, AVLNode*l = NULL, AVLNode*r = NULL, int h = 0) :element(x), left(l), right(r), height(h){}
};
int getHeight(AVLNode* t){
if (t == NULL){
return -1;
}
else{
int leftHeight = getHeight(t->left);
int rightHeight = getHeight(t->right);
return leftHeight > rightHeight ? leftHeight+1 : rightHeight+1;
}
}
//左-左型旋轉
/*
K2-> O K2-> O K1-> O
/ /| / \
K1-> O ----> K1-> O | ----> O O <-K2
/ \ / | /
O O O O O
*/
void rotateWithLeftChild(AVLNode* k2){
AVLNode*k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2 = k1;
}
//右-右型旋轉
/*
K2-> O K2-> O K1-> O
\ |\ / \
K1-> O ----> | O <-K1 ----> K2-> O O
/ \ | \ \
O O O O O
*/
void rotateWithRightChild(AVLNode* k2){
AVLNode* k1 = k2->right;
k2->right = k1->left;
k1->left = k2;
k2 = k1;
}
//左-右型雙旋轉
/*
k3-> O k3-> O k3-> O
/ \ / \ / \
k3->left-> O O O O O O
/ \ ---> / \ ----> / \ / \
O O K3.left->O O O O O O
/ \ / \
O O O O
*/
void doubleWithLeftChild(AVLNode* k3){
//先對k3的左子樹進行右-右型單旋轉
rotateWithRightChild(k3->left);
//再對k3進行左-左型單旋轉
rotateWithLeftChild(k3);
}
//右-左型雙旋轉
/*
O <-K3 O <-K3 O <-K3
/ \ / \ / \
O O <-K3.right O O O O
/ \ -----> / \ -----> / \ / \
O O O O <-K3.right O O O O
/ \ / \
O O O O
*/
void doubleWithRightChild(AVLNode* k3){
//先對右子樹進行左-左型單旋轉
rotateWithLeftChild(k3->right);
//再對K3進行右-右型單旋轉
rotateWithRightChild(k3);
}
//遞迴實現AVL樹插入
void insert(const int &x, AVLNode* t){
if (t == NULL){
t = new AVLNode(x);
}
else if (x < t->element){
insert(x, t->left);
//如果不平衡就調整
//在左子樹插入,用左高度-右高度
if (getHeight(t->left) - getHeight(t->right) == 2){
//如果是左-左型
if (x < t->left->element){
//進行單旋轉
rotateWithLeftChild(t);
}
//如果是左-右型
else{
//進行雙旋轉
doubleWithLeftChild(t);
}
}
}
else if (t->element < x){
insert(x, t->right);
//如果不平衡就調整
//在右子樹插入,用右高度-左高度
if (getHeight(t->right) - getHeight(t->left) == 2){
//如果是右-右型
if (x > t->right->element){
//進行單旋轉
rotateWithRightChild(t);
}
//如果是右-左型
else{
//進行雙調整
doubleWithRightChild(t);
}
}
}
else{
;
}
}
//非遞迴實現AVL樹插入
//利用棧來儲存每個節點的父節點,實現自底向上檢索插入路徑上的每個節點是否平衡
void insert_2(const int & x, AVLNode*tree){
AVLNode * t = tree;
std::stack<AVLNode*> route;
//插入
while (true){
if (!t){
t = new AVLNode(x);
route.push(t);
break;
}
else if (t->element < x){
route.push(t);
t = t->right;
continue;
}
else if (x < t->element){
route.push(t);
t = t->left;
continue;
}
else{ ; }
}
AVLNode *father, *son;
//調整
while (true){
son = route.top();
route.pop();
//當棧裡只有一個節點時,說明自底向上回溯只剩根節點,則退出迴圈
if (route.empty()){
break;
}
father = route.top();
route.pop();
//son節點在father節點的左邊
if (son->element < father->element){
//如果不平衡
if (getHeight(father->left) - getHeight(father->right) == 2){
/*
判斷插入的x在son節點的左還是右
實質是判斷“一”字形還是“之”字形
*/
if (son->element < x){ //x在son節點的右邊
//說明是“之”字形
doubleWithLeftChild(father);
}
else if(x < son->element){ //x在son節點的左邊
//說明是“一”字形
rotateWithLeftChild(father);
}
else{ //son節點是x
//不可能產生不平衡
return;
}
}
route.push(father);
}
//son節點在father節點的右邊
else{
//如果不平衡
if (getHeight(father->right) - getHeight(father->left) == 2){
if (son->element < x){
//"一"字形
rotateWithRightChild(father);
}
else{
doubleWithRightChild(father);
}
}
route.push(father);
}
}
}