AVL樹C++實現(插入,刪除,查詢,清空,遍歷操作)
阿新 • • 發佈:2018-12-13
AVL.h檔案程式碼
#pragma once #include<iostream> #include<stack> #include <assert.h> using namespace std; using namespace std; template<class T> struct AVLNode{ T data; AVLNode<T>*left, *right; int bf; AVLNode() :left(NULL), right(NULL), bf(0) {} AVLNode(T d, AVLNode<T>*l=NULL,AVLNode<T>*r=NULL):data(d),left(l),right(r),bf(0){} }; template<class T> class AVLTree { public: AVLTree():root(NULL){} ~AVLTree() {}; AVLTree(T Ref):Refvalue(Ref),root(NULL){} bool insert(AVLNode<T>*&ptr, T&e1); bool Remove(AVLNode<T>*&ptr, T x); void RotateL(AVLNode<T>*&ptr); void RotateR(AVLNode<T>*&ptr); void PrintBinTree(AVLNode<T>*&t, int level); void RotateLR(AVLNode<T>*&ptr); void RotateRL(AVLNode<T>*&ptr); AVLNode<T>* search(const T x, AVLNode<T>*ptr); friend istream& operator>>(istream&, AVLTree<T>& Tree); friend ostream& operator<<(ostream&, AVLTree<T>&Tree); void Delete(AVLNode<T>*ptr); void output(AVLNode<T>*ptr, ostream&out); AVLNode<T>*root; T Refvalue; private: }; template<class T> void AVLTree<T>::RotateL(AVLNode<T>*&ptr) { AVLNode<T>*subL = ptr; ptr = subL->right; subL->right = ptr->left; ptr->left = subL; ptr->bf = subL->bf = 0; } template<class T> void AVLTree<T>::RotateR(AVLNode<T>*&ptr) { AVLNode<T>*subR = ptr; ptr = subR->left; subR->left = ptr->right; ptr->right = subR; ptr->bf = subR->bf = 0; } template<class T> void AVLTree<T>::RotateLR(AVLNode<T>*&ptr) { AVLNode<T>*subR = ptr, *subL = subR->left; ptr = subL->right; subL->right = ptr->left; ptr->left = subL; if (ptr->bf <= 0)subL->bf = 0; else subL->bf = -1; subR->left = ptr->right; ptr->right = subR; if (ptr->bf == -1)subR->bf = 1; else subR->bf = 0; ptr->bf = 0; } template<class T> void AVLTree<T>::RotateRL(AVLNode<T>*&ptr) { AVLNode<T>*subL = ptr, *subR = subL->right; ptr = subR->left; subR->left = ptr->right; ptr->right = subR; if (ptr->bf >= 0)subR->bf = 0; else subR->bf = 1; subL->right = ptr->left; ptr->left = subL; if (ptr->bf == 1)subL->bf = -1; else subL->bf = 0; ptr->bf = 0; } template<class T> bool AVLTree<T>::insert(AVLNode<T>*&ptr, T&e1) { AVLNode<T>*pr = NULL, *p = ptr, *q; int d; stack<AVLNode<T>*>st; while (p!=NULL) { if (e1 == p->data) { cout << "存在,無法插入\n"; return false; } pr = p; st.push(pr); if (e1 < p->data)p = p->left; else p = p->right; } p = new AVLNode<T>(e1); if (p == NULL) { cout << "記憶體不足" << endl; exit(1); } if (pr == NULL) { ptr = p; return true; }//空樹,根結點插入 if (e1 < pr->data)pr->left = p; else pr->right = p; while (st.empty()==false) { pr = st.top(); st.pop(); if (p == pr->left)pr->bf--; else pr->bf++; if (pr->bf == 0)break;//case 1,平衡退出 if (abs(pr->bf) == 1) {//case 2 p = pr;//回溯 } else {//case 3 |bf|==2 d = (pr->bf < 0) ? -1 : 1; if (p->bf == d) { if (d == -1)RotateR(pr); else RotateL(pr); } else { if (d == -1)RotateLR(pr); else RotateRL(pr); } break; } } if (st.empty() == true)ptr = pr; else { q = st.top(); if (q->data > pr->data)q->left = pr; else q->right = pr; } return true; } //template<class T> istream& operator >>(istream& in, AVLTree<int>& Tree) { int item; in >> item; while (item!=Tree.Refvalue) { Tree.insert(Tree.root,item); in >> item; } return in; } //template<class T> ostream& operator<<( ostream&out, AVLTree<int>&Tree) { out << "中序遍歷輸出各個結點數值:" << endl; Tree.output(Tree.root,out); out << endl; return out; } template<class T> void AVLTree<T>::output(AVLNode<T>*ptr, ostream&out) { if (ptr != NULL) { output(ptr->left, out); cout << ptr->data << " "; output(ptr->right, out); } } template<class T> AVLNode<T>* AVLTree<T>::search(const T x, AVLNode<T>*ptr) { if (ptr == NULL)return NULL; else if (x < ptr->data)return search(x, ptr->left); else if (x > ptr->data)return search(x, ptr->right); else return ptr; } template<class T> void AVLTree<T>::Delete(AVLNode<T>*ptr) { if (ptr != NULL){ Delete(ptr->left); Delete(ptr->right); delete ptr; } } template <class T> void AVLTree<T>::PrintBinTree(AVLNode<T>*&t, int level) { if (t == NULL)return; PrintBinTree(t->right, level + 1); for (int i = 0; i < 4 * (level - 1); i++)cout << " "; cout << t->data << endl; PrintBinTree(t->left, level + 1); } template<class T> bool AVLTree<T>::Remove(AVLNode<T>*&t, T val) { assert(t != nullptr); AVLNode<T> *tmp = t; AVLNode<T> *pre_tmp = nullptr; AVLNode<T> *ppre_tmp = nullptr; AVLNode<T> *it_tmp = nullptr; stack<AVLNode<T>*> st; int sign, lable; //符號標記 int flag = 0; //子樹標記,下文具體解釋 while (tmp != nullptr) { if (tmp->data == val) //找到跳出迴圈 break; pre_tmp = tmp; st.push(pre_tmp); if (tmp->data > val) tmp = tmp->left; else tmp = tmp->right; } if (tmp == nullptr) //未找到,返回 return false; else if (tmp->left!= nullptr && tmp->right != nullptr) { pre_tmp = tmp; //將有兩個孩子的節點轉化為只有一個孩子的節點,方法是尋找它中序遍歷的直接前驅或後繼 st.push(pre_tmp); it_tmp = tmp->left; while (it_tmp->right!= nullptr) { pre_tmp = it_tmp; st.push(pre_tmp); it_tmp = it_tmp->right; } tmp->data = it_tmp->data; //覆蓋要刪除的節點 tmp = it_tmp; //tmp指向要刪除的節點,函式結束前會delete tmp } if (tmp->left!= nullptr) { //這樣的判斷方式會導致刪除一個節點下兩個沒有孩子節點的節點時,由於左孩子均為空,直接跳入else it_tmp = tmp->left; } else { it_tmp = tmp->right; } if (pre_tmp == nullptr) t = it_tmp; else { if (pre_tmp->left== tmp) { //上面直接跳入else,但我們在此處加上flag,用來識別它到底是pre_tmp的左孩子還是右孩子。 flag = 0; pre_tmp->left= it_tmp; } else { flag = 1; pre_tmp->right = it_tmp; } while (!st.empty()) { pre_tmp = st.top(); st.pop(); if (pre_tmp->left == it_tmp && flag == 0)//此處flag=0,防止pre_tmp的左孩子為空,右孩子同樣為空,直接進入else pre_tmp->bf++; else pre_tmp->bf--; if (!st.empty()) { ppre_tmp = st.top(); if (ppre_tmp->left == pre_tmp) { sign = -1; //sign用來識別是祖父節點的左孩子還是右孩子,下文連結會用上 flag = 0; } else { sign = 1; flag = 1; } } else sign = 0; //棧空,它的祖先節點不存在,pre_tmp即為根節點,但是這裡也要寫上,否則sign的值會遺留下來 if (pre_tmp->bf == -1 || pre_tmp->bf == 1) break; //已經平衡,直接跳出 if (pre_tmp->bf != 0) { //m_bf為+2/-2 if (pre_tmp->bf < 0) { lable = -1; //lable表示父節點符號,下面會用來區分同號異號 it_tmp = pre_tmp->left; } else { lable = 1; it_tmp = pre_tmp->right; } if (it_tmp->bf == 0) { //pre_tmp的較高子樹的頭節點m_bf為0 if (lable == -1) { RotateR(pre_tmp); pre_tmp->bf = 1; pre_tmp->right->bf = -1; } else { RotateL(pre_tmp); pre_tmp->bf = -1; pre_tmp->left->bf = 1; } break; //直接跳出,並沒有連結,需要下文寫上鍊接 } if (it_tmp->bf == lable) { //同號 lable == 1 ? RotateL(pre_tmp) : RotateLR(pre_tmp); } else { //異號 lable == -1 ? RotateLR(pre_tmp): RotateRL(pre_tmp); } //sign == -1 ? ppre_tmp->left_child = pre_tmp //不能寫成這樣,因為sign值可能為0,會直接進入後者 // : ppre_tmp->right_child = pre_tmp; //!!!!! sign maybe 0 ! not only1 or -1 !!! warning! if (sign == -1) ppre_tmp->left = pre_tmp; else if (sign == 1) //else if正確方式 ppre_tmp->right = pre_tmp; } it_tmp = pre_tmp; //回溯 } if (st.empty()) //棧為空,根節點 t = pre_tmp; else { //這一段else參考書上沒有,書是錯的,如果不寫此處,290break直接跳出while迴圈,會導致連結不上,資料丟失 ppre_tmp = st.top(); if (ppre_tmp->data > pre_tmp->data) ppre_tmp->left = pre_tmp; else ppre_tmp->right = pre_tmp; } } delete tmp; tmp = nullptr; return true; }
源cpp程式碼
#include"AVL.h" #include<iostream> using namespace std; int main() { AVLTree<int> tree; cout << "建立AVL樹,終止表示設為0" << endl; tree.Refvalue = 0; cout << "1:建樹\n2:插入\n3:搜尋\n4:刪除\n5:輸出\n6:清空\n7:退出\n"; bool over = false; while (!over) { int c; int num; cin >> c; switch (c) { case 1: { cin >> tree; cout << "建樹完畢\n"; break; } case 2: { cin >> num; tree.insert(tree.root, num); cout << "插入完畢\n"; break; } case 3: {cin >> num; if (tree.search(num, tree.root) != NULL)cout << num << "已經被找到\n"; else cout << num << "不存在\n"; break; } case 4: {cin >> num; tree.Remove(tree.root, num); } case 5: {cout << tree; cout << " 凹凸列印AVL樹\n"; tree.PrintBinTree(tree.root, 1); break; } case 6: { //tree.Delete(tree.root); tree.root=NULL; break; } case 7:{ over = true; break; } default:cout << "輸入有誤\n"; break; } } char ch; cin >> ch; }