資料結構學習-AVL平衡樹
環境:C++ 11 + win10
IDE:Clion 2018.3
AVL平衡樹是在BST二叉查詢樹的基礎上添加了平衡機制。
我們把平衡的BST認為是任一節點的左子樹和右子樹的高度差為-1,0,1中的一種情況,即不存在相差兩層及以上。
所謂平衡機制就是BST在理想情況下搜尋複雜度是o(logn)
但是如果在(存在某一節點,該節點的左子樹的高度與右子樹的高度差>1)這種狀況下,複雜度會超過o(logn)
舉個極端的例子如加入1,2,3,4,BST就退化為一個線性的連結串列,複雜度變成了o(n)
為了避免這種情況,我們在BST中引入平衡操作(旋轉操作),使得BST始終不存在左右子樹超過1高度差的節點。
本次程式碼基於我的另一篇部落格的基礎之上,有需要可以翻看 https://www.cnblogs.com/cyrio/p/10118132.html
平衡機制主要通過反轉完成,經過歸納,可能出現以下四種不平衡的情況:LL、LR、RL、RR
L=left R=right
我們將不平衡點設為X點,以LR為例,第一個L表示X點的左子樹比右子樹層數多(>1),第二個R表示多出的那部分在X點的左子樹的右子樹。(不管他是在X的左子樹的右子樹的左右哪邊,都稱為LR)
如圖:
接下來我們以LL、LR、RR、RL四種情況討論。
1、LL:
通俗的講就是把K2從K1那扯下來,然後把Y移到K2的左子樹,最後把K2移到K1的右子樹。
2、RR:
與LL同理,把K1先扯下來,再把Y接到K1的右側,再把K1作為左子樹接到K2。
3、LR:
LR需要先做一次RR再做一次LL:
先把K1從K2那扯下來,讓K2和K3連,然後把B作為K1的右子樹,再把K1連到K2的左子樹上。
然後再做LL,把K3從K2上面扯下來,讓C作為K3的左子樹,再把K3連到K2的右子樹。
4、RL:
先LL再RR,與LR同理。
以上是主要思想的分析,除了旋轉操作,我們還需要新增新的方法:
1、求樹的高度:height方法
2、求某節點的左子樹和右子樹的高度差 :Diff方法
3、一個對整個樹進行判斷,對裡面的X節點進行對應操作:Balance方法
同時AVL中的Insert(插入某一節點)的方法與BST中也略有不同,需要注意的是AVL種的__Insert(PS:帶"__"的表示私有內部介面)的引數中第一個為bstNode<T> * & root (需要&引用)
具體程式碼如下:(此程式碼為完整程式碼,可以直接複製進自己的專案檢視效果)
myBST.h
#ifndef TEST1_MYBST_H #define TEST1_MYBST_H #include <iomanip> #include "bstNode.h" #include <vector> #include <deque> #include <iostream> #include <algorithm> using namespace std; template <typename T> class myBST{ private: bstNode<T> * root = nullptr; bstNode<T> * __search(bstNode<T> * root , const T &key){ if (nullptr == root) return nullptr; if (key == root->data) return root; else if (key < root->data) return __search(root->left, key); else return __search(root->right, key); } //查詢關鍵字是否存在 bstNode<T> * __treeMin(bstNode<T> * root , bstNode<T> * &parent){ bstNode<T> * curr = root; while(curr->left!= nullptr){ parent = curr; curr = curr->left; } return curr; } //返回最小節點(一路向左) bstNode<T> * __Insert(bstNode<T> * &root, const T &key){ if (nullptr == root) { root = new bstNode<T>(key); return root; }//遞迴返回條件 else if (key < root->data) { root->left = __Insert(root->left,key);//遞迴左子樹 //balance operation root = __Balance(root);//平衡操作包含了四種旋轉 } else if (key>root->data) { root->right = __Insert(root->right,key);//遞迴右子樹 //balance operation root = __Balance(root);//平衡操作包含了四種旋轉 } return root; } //插入指定值 bool __Delete(const T &key){ bool found = false;//儲存有沒有找到key的變數 if(isEmpty()){ cerr<<"BST為空"<<endl; return false; } bstNode<T> * curr = root; bstNode<T> * parrent = nullptr; while(curr!= nullptr) { if (key == curr->data) { found = true; break; } else { parrent = curr; if (key < curr->data) curr = curr->left; else curr = curr->right; } } if(!found){ cerr<<"未找到key!"<<endl; return false; } if (parrent == nullptr){//刪除根節點 root = nullptr; delete(curr); return true; } /* 刪除的節點有三種可能: 1、葉子結點 2、一個孩子的節點 3、兩個孩子的節點 */ if (__isLeaf(curr)){ //刪除的點是葉子結點 if(parrent->left==curr) parrent->left= nullptr; else parrent->right= nullptr; delete(curr); return true; } else if(__isNodeWithTwoChild(curr)){ //是兩個孩子的節點 //以當前右子樹中的最小值取代他 bstNode<T> * parrent = curr; bstNode<T> * tmp = __treeMin(curr->right,parrent); curr->data = tmp->data; if(parrent->right==tmp) parrent->right== nullptr; else parrent->left== nullptr; delete(tmp); return true; } else{ //只有一個孩子的節點 if(curr->left!= nullptr){ if(curr->left == curr){ parrent->left=curr->left; delete(curr); return true; } else{ parrent->right=curr->right; delete(curr); return true; } } if(curr->right!= nullptr){ if(curr->left == curr){ parrent->left=curr->left; delete(curr); return true; } else{ parrent->right=curr->right; delete(curr); return true; } } } return false; } //刪除指定值 bool __isLeaf(bstNode<T> * const & root){ if(root->left== nullptr && root->right== nullptr) return true; else return false; }//判斷是否是葉子節點 bool __isNodeWithTwoChild(bstNode<T> * const & root){ if(root->left!= nullptr && root->right!= nullptr) return true; else return false; }//判斷是否有兩個孩子 void __InorderTraversal(bstNode<T> *root,std::vector<int>&result){ if(nullptr == root) return; __InorderTraversal(root->left,result); cout<<root->data<<" "; result.push_back(root->data); __InorderTraversal(root->right,result); }//中序遍歷 void __PreorderTraversal(bstNode<T> *root,std::vector<int>&result){ if(nullptr == root) return; cout<<root->data<<" "; result.push_back(root->data); __InorderTraversal(root->left,result); __InorderTraversal(root->right,result); }//前序遍歷 void __PostorderTraversal(bstNode<T> *root,std::vector<int>&result){ if(nullptr == root) return; __InorderTraversal(root->left,result); __InorderTraversal(root->right,result); cout<<root->data<<" "; result.push_back(root->data); }//後序遍歷 void __DeleteAllNodes(bstNode<T> *root){ if (root == nullptr) return; __DeleteAllNodes(root->left); __DeleteAllNodes(root->right); __Delete(root->data); }//刪除所有節點 void __BFTraversal(vector<T>&result) { deque<bstNode<T> *> TQueue; bstNode<T> *pointer = root; if (pointer != nullptr) { TQueue.push_back(pointer); } while (!TQueue.empty()) { pointer = TQueue.front(); TQueue.pop_front(); cout << pointer->data << " "; result.push_back(pointer->data); if (pointer->left != nullptr) TQueue.push_back(pointer->left); if (pointer->right != nullptr) TQueue.push_back(pointer->right); } } //廣度搜索來進行周遊 void __Graph(int indent,bstNode<T>* root){ if(root != 0){ __Graph(indent + 8, root->right); cout<<setw(indent)<<" "<<root->data<<endl; __Graph(indent + 8, root->left); } } //橫著畫圖的內部介面 bstNode<T> * __GetRoot(){ return root; } //返回根節點的內部介面 //以下為AVL平衡樹新加的方法 int __height(const bstNode<T>* root){ if(root == nullptr){ return 0; } return max(__height(root->left),__height(root->right))+1; } //求樹的高度 int __diff(const bstNode<T>* root){ return __height(root->left)-__height(root->right); } //求節點的高度差(平衡因子) bstNode<T> * __ll__Rotation(bstNode<T> * root){ bstNode<T> * tmp; tmp = root->left; root->left = tmp->right; tmp->right = root; return tmp; } //單旋轉-左左 bstNode<T> * __rr__Rotation(bstNode<T> * root){ bstNode<T> * tmp; tmp = root->right; root->right = tmp->left; tmp->left = root; return tmp; } //單旋轉-右右 bstNode<T> * __lr__Rotation(bstNode<T> * root){ bstNode<T> * tmp; tmp = root->left; root->left = __rr__Rotation(tmp); return __ll__Rotation(root); } //雙旋轉-左右型,先右後左轉(注意此處相反) bstNode<T> * __rl__Rotation(bstNode<T> * root){ bstNode<T> * tmp; tmp = root->right; root->right = __ll__Rotation(tmp); return __rr__Rotation(root); } //雙旋轉-右左型,先左後右轉 bstNode<T> * __Balance(bstNode<T> * root){ int balanceFactor = __diff(root);//__diff用來計算平衡因子(左右子樹高度差) if (balanceFactor > 1)//左子樹高於右子樹 { if (__diff(root->left) > 0)//左左外側 root=__ll__Rotation(root); else//左右內側 root=__lr__Rotation(root); } else if (balanceFactor < -1)//右子樹高於左子樹 { if (__diff(root->right) > 0)//右左內側 root=__rl__Rotation(root); else//右右外側 root=__rr__Rotation(root); } return root; } //平衡的內部操作 public: myBST(){ root = nullptr; } //預設構造 myBST(vector<T> arr){ root = nullptr; for(int i =0;i<(T)arr.size();i++){ Insert(arr[i]); } } myBST(T * arr,int len){ root = nullptr; for(int i =0;i<len;i++){ __Insert(*(arr+i)); } } ~myBST(){ bstNode<T> * curr = root; __DeleteAllNodes(curr); }//析構 bool isEmpty() const{ return root == nullptr; }//判斷樹空 bool search(const T &key){ bstNode<T> * temp = __search(root, key); return (temp == nullptr) ? false : true; }//查詢關鍵字是否存在的對外介面 bool Insert(const T &key){ return __Insert(root,key); }//插入節點的外部介面 bool Delete(const T &key){ return __Delete(key); }//刪除節點的外部介面 void InorderTraversal(vector<T>&result){ __InorderTraversal(root, result); }//中序遍歷的外部介面 void PreorderTraversal(vector<T>&result){ __PreorderTraversal(root, result); }//前序遍歷的外部介面 void PostorderTraversal(vector<T>&result){ __PostorderTraversal(root, result); }//後序遍歷的外部介面 void BFTraversal(vector<T>&result){ return __BFTraversal(result); } //廣度搜索外部介面 void Graph(int indent,bstNode<T>* root){ return __Graph(indent,root); } //橫著畫圖的外部介面 bstNode<T> * GetRoot(){ return __GetRoot(); } //返回根節點的外部介面 }; #endif //TEST1_MYBST_H
bstNode.h
#ifndef TEST1_BSTNODE_H #define TEST1_BSTNODE_H template <typename T> class bstNode{ public: T data; bstNode* left; bstNode* right; bstNode(){ data = 0; left = nullptr; right = nullptr; } bstNode(T val){ data = val; left = nullptr; right = nullptr; } }; #endif //TEST1_BSTNODE_H
main.cpp
#include <iostream> #include <vector> #include "myBST.h" #include "bstNode.h" using namespace std; int main() { vector<int> in = {7,6,5,13,17,22,10,3,2,1}; myBST<int> bst(in); bst.Delete(5); bst.Insert(4); bool found = bst.search(4); if(!found) cout<<"not found!"<<endl; else cout<<"found!"<<endl; vector<int> result; cout<<"InorderTravelsal: "; bst.InorderTraversal(result); cout<<endl<<"PreorderTravelsal: "; bst.PreorderTraversal(result); cout<<endl<<"PostorderTraversal: "; bst.PostorderTraversal(result); cout<<endl<<"BFTraversal: "; bst.BFTraversal(result); cout<<endl<<"Graph:"<<endl; bstNode<int>* pointer = bst.GetRoot(); bst.Graph(0,pointer); return 0; }
參考:https://blog.csdn.net/zhangxiao93/article/details/51459743