之前的博客,实现了数据结构中最基本的树形结构——二叉搜索树,下一步实现AVL树。这真的是很头疼的一颗树,无论是插入还是删除,都得分多种情况来讨论,其中的控制逻辑很繁琐。在编写代码之前,首先要想清楚在插入和删除的时候各个分支到底怎么处理,然后去编写代码。起码我现在看这部分内容,还是十分拧巴。多看看的话,应该会熟悉一点吧。
首先编写test.h:
#include<iostream> #include<stack> #include<assert.h> using namespace std; template<class Type> class AVLTree; template<class Type> class AVLNode { friend class AVLTree<Type>; public: AVLNode() : data(Type()), leftChild(NULL), rightChild(NULL),bf(0) {} AVLNode(Type d, AVLNode<Type>*left=NULL, AVLNode<Type>*right=NULL) :data(d), leftChild(left), rightChild(right),bf(0) {} ~AVLNode() {} public: Type GetData()const {return data;} AVLNode<Type>* GetLeftChild()const {return leftChild;} AVLNode<Type>* GetRightChild()const {return rightChild;} public: void SetData(Type d) {data = d;} void SetLeftChild(AVLNode<Type> *left) {leftChild = left;} void SetRightChild(AVLNode<Type> *right) {rightChild = right;} private: Type data; AVLNode<Type> *leftChild; AVLNode<Type> *rightChild; int bf; }; template<class Type> class AVLTree { public: AVLTree() : root(NULL) {} public: bool Insert(const Type &x) { return Insert(root, x); } bool Remove(const Type &x) { return Remove(root, x); } protected: //bool Remove(AVLNode<Type> *&t, const Type &x); bool Remove(AVLNode<Type> *&t, const Type &x) { AVLNode<Type> *pr = NULL, *p = t, *q, *ppr; int d, dd = 0; stack<AVLNode<Type>*> st; while (p != NULL) { if (x == p->data) break; pr = p; st.push(pr); if (x < p->data) { p = p->leftChild; } else { p = p->rightChild; } } if(p == NULL) return false; if (p->leftChild != NULL && p->rightChild != NULL) { pr = p;st.push(pr); q = p->leftChild; while (q->rightChild != NULL) { pr = q;st.push(pr); q = q->rightChild; } p->data = q->data; p = q; } if(p->leftChild != NULL) q = p->leftChild; else q = p->rightChild; if(pr == NULL) t = q; else{ if(pr->leftChild == p) pr->leftChild = q; else pr->rightChild = q; while(st.empty() == false) { st.pop(); if(pr->rightChild == q) pr->bf--; else pr->bf++; if(st.empty() == false) { ppr = st.top(); dd = (ppr->leftChild == pr) ? -1 : 1; } else dd = 0; if(pr->bf == 1 || pr->bf == -1) break; if(pr->bf != 0) { if(pr->bf < 0){d = -1; q = pr->leftChild;} else{d = 1; q = pr->rightChild;} if(q->bf == 0) { if(d == -1) {RotateR(pr);pr->bf = 1; pr->leftChild->bf = -1;} else{RotateL(pr); pr->bf = -1; pr->rightChild->bf = 1;} break; } if(q->bf == d) { if(d == -1) RotateR(pr); else RotateL(pr); } else { if(d == -1) RotateLR(pr); else RotateRL(pr); } if(dd == -1) ppr->leftChild = pr; else if(dd == 1) ppr->rightChild = pr; } q = pr; } if(st.empty() == true) t = pr; } delete p ;return true; } bool Insert(AVLNode<Type> *&t, const Type &x) { AVLNode<Type> *pr = NULL; AVLNode<Type> *p = t; stack<AVLNode<Type>*> st; while(p != NULL) { if(x == p->data) return false; pr = p; st.push(pr); if(x < p->data) p = p->leftChild; else p = p->rightChild; } p = new AVLNode<Type>(x); if(pr == NULL) { t = p; return true; } if(p->data < pr->data) pr->leftChild = p; else pr->rightChild = p; while(!st.empty()) { pr = st.top(); st.pop(); if(pr->leftChild == p) pr->bf--; else pr->bf++; if(pr->bf == 0) break; else if(pr->bf==1 || pr->bf==-1) p = pr; else { if(pr->bf < 0) { if(p->bf < 0) // / { RotateR(pr); } else // < { RotateLR(pr); } } else { if(p->bf > 0) // \ { RotateL(pr); } else // > { RotateRL(pr); } } break; } } if(st.empty()) t = pr; else { AVLNode<Type> *q = st.top(); if(q->data > pr->data) q->leftChild = pr; else q->rightChild = pr; } return true; } protected: void RotateR(AVLNode<Type> *& ptr) { AVLNode<Type> *subR = ptr; ptr = subR->leftChild; subR->leftChild = ptr->rightChild; ptr->rightChild = subR; ptr->bf = subR->bf = 0; } void RotateL(AVLNode<Type> *& ptr) { AVLNode<Type> *subL = ptr; ptr = subL->rightChild; subL->rightChild = ptr->leftChild; ptr->leftChild = subL; ptr->bf = subL->bf = 0; } void RotateLR(AVLNode<Type> *& ptr) { AVLNode<Type>*subR = ptr; AVLNode<Type>*subL = ptr->leftChild; ptr = subL->rightChild; //左转 subL->rightChild = ptr->leftChild; ptr->leftChild = subL; if(ptr->bf <= 0) subL->bf = 0; else subL->bf = -1; subR->leftChild = ptr->rightChild; ptr->rightChild = subR; if(ptr->bf >= 0) subR->bf = 0; else subR->bf = 1; ptr->bf = 0; } void RotateRL(AVLNode<Type> *& ptr) { AVLNode<Type> *subL = ptr; AVLNode<Type> *subR = ptr->rightChild; ptr = subR->leftChild; subR->leftChild = ptr->rightChild; ptr->rightChild = subR; if(ptr->bf >= 0) subR->bf = 0; else subR->bf = 1; subL->rightChild = ptr->leftChild; ptr->leftChild = subL; if(ptr->bf == 1) subL->bf = -1; else subL->bf = 0; ptr->bf = 0; } private: AVLNode<Type> *root; };测试程序test.cpp:
#include"Test.h" void main() { int ar[] = {16,3,7,11,9,26,18,14,15}; int n = sizeof(ar) / sizeof(int); AVLTree<int> avl; for(int i=0; i<n; ++i) { avl.Insert(ar[i]); } avl.Remove(11); return; }我的笔记本上有三个C++的编译器,分别是年代很久远的VC++6.0,clion,codeblocks,后面两个都是gcc的编译器。我本人比较偏爱cb,但是它在调试查看变量反面实在是短板,前面两个表现都不错,值得表扬。我就在想是不是cb的设置有问题呢?
AVL树真的很难啊。。。
