1. 程式人生 > >AVL樹的旋轉和插入

AVL樹的旋轉和插入

包含了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); } } }