【輸入】
可以對AVL樹進行插入或刪除數字
【輸出】
依前序追蹤輸出AVL樹
【完整程式碼】
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
class Node{
private:
int data;
int height;
Node *left, *right;
public:
Node(int val){ data = val; left = right = NULL; height = 1;}
friend class AVLTree;
};
class AVLTree{
private:
int height(Node* node){
return (!node)? 0: node->height;
}
int getBF(Node* node){
return (!node)? 0: height(node->left) - height(node->right);
}
//旋轉方法
Node* rotate(Node* old_rootT, char direct) {
//重新定義此子樹的rootT節點
Node *new_rootT = (direct=='L')? old_rootT->right: old_rootT->left; //若左轉,新的rootT會是舊rootT->R,若右轉,新的rootT會是舊rootT->L
Node *temp = (direct=='L')? new_rootT->left: new_rootT->right; //若左轉,暫存子樹會是舊rootT->R->L(即新的rootT>L),若右轉,暫存子樹會是舊rootT->L->R(即新的rootT>R)
//旋轉
if(direct=='L'){ //若左轉
new_rootT->left = old_rootT; //舊rooT會變成新的rootT->L
old_rootT->right = temp; //舊rootT->R會是暫存子樹temp(即舊rootT->R->L, 亦即新的rootT->L)
}else{ //若右轉
new_rootT->right = old_rootT; //舊rooT會變成新的rootT->R
old_rootT->left = temp; //舊rootT->L會是暫存子樹temp(即舊rootT->L->R, 亦即新的rootT->R)
}
//更新有改變到的高度(從底至上),所以先update舊rootT
old_rootT->height = max(height(old_rootT->left), height(old_rootT->right)) + 1;
new_rootT->height = max(height(new_rootT->left), height(new_rootT->right)) + 1;
return new_rootT;
}
//插入遞迴式
Node* insertRecursive(Node* rootT, int val){
//使用一般的BST樹插入方法插入數字
if(!rootT) return (new Node(val)); //若目前節點 (或作 目前子樹的根) 為空,即樹葉節點插入新節點至樹葉 (回傳給上一層,此例中上一層也等同rootT,因為是用 rootT = insert(rootT, val)呼叫 )
else if(val < rootT->data) rootT->left = insertRecursive(rootT->left, val); //若 數字 < 目前節點,則插入左子樹 (即:rootT->左子 = insert(rootT->左子) 會 return 一個插入完數字 的子樹 的rootT 給 rootT->左子)
else if(val > rootT->data) rootT->right = insertRecursive(rootT->right, val); //若 數字 > 目前節點,則插入右子樹
else return rootT; //二元樹原則上非key-value數對型態者,不會有重複值
//把rootT 回傳給rootT (即:把自己丟回給自己,不作修改)
rootT->height = max(height(rootT->left), height(rootT->right)) + 1; //插入後,更新目前這個節點的樹高 (取左右子樹高之大者 + 1(自己))
int bf = getBF(rootT); //取得平衡因子
//process if abs(bf)>1
if(bf > 1 && val < rootT->left->data){ //(平衡因子>1) => 左子樹高,前面必插左邊; (插入數 < 左子樹值) => 前面必插左子樹的左邊 {LL}
return rotate(rootT, 'R'); //自己 (目前子樹) 右轉,然後把rootT 回傳給上一層 (同前面提到,此例中上一層也等同rootT,即原本呼叫這個函數的人rootT = insert(rootT, val) )
}
if(bf > 1 && val > rootT->left->data){ //(平衡因子>1) => 左子樹高,前面必插左邊; (插入數 > 左子樹值) => 前面必插左子樹的右邊 {LR}
rootT->left = rotate(rootT->left, 'L'); //自己的左邊 (目前子樹的左子樹) 先左轉
return rotate(rootT, 'R'); //自己 (目前子樹) 再右轉
}
if(bf < -1 && val > rootT->right->data){ //(平衡因子< -1) => 右子樹高,前面必插右邊; (插入數 > 右子樹值) => 前面必插右子樹的右邊 {RR}
return rotate(rootT, 'L'); //自己 (目前子樹) 左轉
}
if(bf < -1 && val < rootT->right->data){ //(平衡因子< -1) => 右子樹高,前面必插右邊; (插入數 < 右子樹值) => 前面必插右子樹的左邊 {RL}
rootT->right = rotate(rootT->right, 'R'); //自己的右邊 (目前子樹的左子樹) 先右轉
return rotate(rootT, 'L'); //自己 (目前子樹) 再左轉
}
return rootT;
}
//找子樹中最小的樹 (從根開始往左走直到不能走)
Node* minValue(Node* rootT){
Node* ptr = rootT;
while(ptr->left)
ptr = ptr->left;
return ptr;
}
//自AVL樹中刪除
Node* removeRecursive(Node* rootT, int val){
//使用一般的BST樹插入方法刪除數字
if(!rootT) return NULL; //若為空值,那不用刪除,直接回傳給剛剛叫他的人(亦作 return rootT;) (rootT==NULL 即剛剛叫他的人傳入的子樹為空)
else if(val < rootT->data) rootT->left = removeRecursive(rootT->left, val); //若 數字 < 目前節點,要刪除的數字在目前子樹的左子樹
else if(val > rootT->data) rootT->right = removeRecursive(rootT->right, val); //若 數字 > 目前節點,要刪除的數字在目前子樹的右子樹
else{ //上面都不成立,即找到相等的數,進入刪除階段
if(!rootT->left || !rootT->right){ //若目前節點的子樹數量為 0(無子樹) 或 只有單邊子樹
Node* childT = (rootT->left)? rootT->left: rootT->right; //暫存左或右子樹
delete rootT; //釋放目前子樹樹根記憶體
rootT = childT; //令左或右子樹樹根為樹根 (左或右樹直接上拉)
}else{ //若目前節點 左、右子樹皆有
Node* minT = minValue(rootT->right); //取得 右子樹最小的節點
rootT->data = minT->data; //設目前子樹樹根的數字 為剛剛找到的節點的數字
rootT->right = removeRecursive(rootT->right, minT->data); //刪除剛剛找到的節點 (註:因為右子樹最小的節點必無左子樹,故遞迴結果必為第1或第2個if)
}
}
if(!rootT) return rootT; //若目前子樹樹根為空,必平衡且樹高為0,直接回傳
rootT->height = max(height(rootT->left), height(rootT->right)) + 1; //更新目前這個節點的樹高
int bf = getBF(rootT); //取得平衡因子
//process if abs(bf)>1
if(bf > 1 && getBF(rootT->left) >= 0){ //(平衡因子>1) => 左子樹高,前面必刪右邊; (左子節點平衡因子>=0的話) => 右轉後必變為-1或0,故不用先轉; {LL}
return rotate(rootT, 'R'); //自己 (目前子樹) 右轉
}
if(bf > 1 && getBF(rootT->left) < 0){ //(平衡因子>1) => 左子樹高,前面必刪右邊; (左子節點平衡因子<0的話) => 右轉後必變為-2,故要先轉; {LR}
rootT->left = rotate(rootT->left, 'L'); //自己的左邊 (目前子樹的左子樹) 先左轉
return rotate(rootT, 'R'); //自己 (目前子樹) 再右轉
}
if(bf < -1 && getBF(rootT->right) <= 0){ //(平衡因子< -1) => 右子樹高,前面必刪左邊; (右子節點平衡因子<=0的話) => 左轉後必變為1或0,故不用先轉; {RR}
return rotate(rootT, 'L'); //自己 (目前子樹) 左轉
}
if(bf < -1 && getBF(rootT->right) > 0){ //(平衡因子< -1) => 右子樹高,前面必刪左邊; (右子節點平衡因子>0的話) => 左轉後必變為2,故要先轉; {RL}
rootT->right = rotate(rootT->right, 'R'); //自己的右邊 (目前子樹的右子樹) 先右轉
return rotate(rootT, 'L'); //自己 (目前子樹) 再左轉
}
return rootT;
}
public:
Node *root;
AVLTree(){ root = NULL; }
void insert(int val) {
root = insertRecursive(root, val);
}
void remove(int val) {
root = removeRecursive(root, val);
}
//前序印出AVL樹
void preOrder(Node* root) {
if(root) {
cout << root->data << "\t";
root->left? (cout << root->left->data << "\t"): (cout << "Nan\t");
root->right? (cout << root->right->data << endl): (cout << "Nan" << endl);
preOrder(root->left);
preOrder(root->right);
}
}
};
int main(void){
AVLTree AVLTree;
int val;
char SENT;
//對AVL樹的操作
cout << "<1: 插入> <2: 刪除> <3: 列出(前序)> <q: 離開>" << endl << "選擇操作 : ";
cin >> SENT;
while(SENT != 'q'){
switch(SENT) {
case '1':
cout << "輸入要插入的數: ";
cin >> val;
AVLTree.insert(val);
break;
case '2':
cout << "輸入要刪除的數: ";
cin >> val;
AVLTree.remove(val);
break;
case '3':
cout << endl << "樹根節點按前序追蹤排序" << endl;
cout << "樹根\t左子\t右子" << endl;
AVLTree.preOrder(AVLTree.root);
cout << endl;
break;
default:
break;
}
cout << endl << "<1: 插入> <2: 刪除> <3: 列出(前序)> <q: 離開>" << endl << "選擇操作 : ";
cin >> SENT;
}
system("pause");
return 0;
}