二叉樹的查找,插入和刪除操做的時間與樹的高度有關,若是樹儘可能的矮胖,那麼時間就短,那就要是滿二叉樹,或者說滿N叉樹,對於一顆M個節點的滿N叉樹時間複雜度爲,可是維護滿叉樹,難度是很大的。因此AVL樹(平衡樹)放寬了條件,容許左右子樹的高度差在必定的範圍以內,avl樹平衡條件是左右子樹高度相差不能爲2,而不是滿叉樹左右子樹高度相同。AVL是以提出它的兩位蘇聯數學家的名字頭字母命名的。一棵N個節點的AVL樹,高度最高爲1.44logx(N+1)-0.328,比滿二叉樹高度增長44%。node
在avl樹中經過對不知足限制條件的子樹就行旋轉規格來確保av樹的平衡條件一直成立。在AVL樹中有LL,LR,RR和RL四種旋轉方式。.net
下面給出幾個示例:code
依次插入3,5,6,2,1,4blog
按照和二叉樹插入的方式同樣,插入3,5,6:rem
如今不平橫了,3節點左子樹的高度爲-1(空樹爲-1),右子樹爲1,相差爲2,不平衡,插入在3節點的右子樹的右子樹,這種狀況稱爲RR,轉換爲,這樣就平衡了。繼續插入2和1,狀況以下:節點3失去平衡,1插在3的左子樹的左子樹,LL狀況,須要旋轉,以下:樹從新平衡,如今繼續插入4,以下:,節點5失去平衡,4插在它的左子樹的右子樹上,這種狀況爲LR,須要兩次旋轉,第一次爲RR,5的左子樹,而後LL5這棵樹。變換後以下:數學
就不一一分析了,下面是實現代碼。it
/************************************************ * *author:周翔 *e-mail:604487178@qq.com *blog:http://blog.csdn.net/zhx6044 * * *************************************************/ #ifndef AVLTREE_HPP #define AVLTREE_HPP #include "linkQueue.hpp" template <typename T> T max(const T &t1, const T &t2) { return (t1 < t2) ? t2 : t1 ; } template <typename T> class AvlTree { public: AvlTree(); ~AvlTree(); bool find(const T& t) const; bool insert(const T &t); void remove(const T &t); bool isEmpty() const; void clear(); int height(typename AvlTree::node *n); /** * @brief levelTraverse 層虛遍歷 * @param os */ void levelTraverse(std::ostream &os = std::cout) const; private: typedef enum {LEFT, RIGHT} TreeType; struct node { T data; node *lc,*rc; int height;//高度 node():lc(0),rc(0),height(0){ } node(const T &t,node *_lc = 0, node *_rc = 0,int _hei = 0): data(t), lc(_lc), rc(_rc), height(_hei){ } }; node *root; bool insert(const T &t, node *&n); bool remove(const T &t, node *&n); void clear(node *n); //四種旋轉, void LL(node *&n); void RR(node *&n); void LR(node *&n); void RL(node *&n); }; template <typename T> inline AvlTree<T>::AvlTree():root(0) { } template <typename T> AvlTree<T>::~AvlTree() { clear(); } template <typename T> void AvlTree<T>::clear(node *n) { if (n->lc != 0) { clear(n->lc); } if (n->rc != 0) { clear(n->rc); } delete n; } template <typename T> void AvlTree<T>::clear() { if (!isEmpty()) clear(root); } template <typename T> inline bool AvlTree<T>::isEmpty() const { return root == 0; } template <typename T> inline int AvlTree<T>::height(node *n) { return (n == 0) ? -1 : n->height; } template <typename T> void AvlTree<T>::LL(node *&n) { node *p = n;//暫存n n = n->lc;//左子樹做爲根節點 p->lc = n->rc;//右子樹做爲原來根的左子樹 n->rc = p;//原來根節點做爲新節點的右子樹 p->height = max(height(p->lc),height(p->rc)) + 1;//先作子樹的高度 n->height = max(height(n->lc),height(n->rc)) + 1; } template <typename T> void AvlTree<T>::RR(node *&n) { node *p = n; n = n->rc; p->rc = n->lc; n->lc = p; p->height = max(height(p->lc),height(p->rc)) + 1; n->height = max(height(n->lc),height(n->rc)) + 1; } template <typename T> void AvlTree<T>::LR(node *&n) { RR(n->lc); LL(n); } template <typename T> void AvlTree<T>::RL(node *&n) { LL(n->rc); RR(n); } template <typename T> bool AvlTree<T>::find(const T &t) const { node *p = root; while (p != 0 && p->data != t) { if (p->data < t) { p = p->rc; } else { p = p->lc; } } return ((p == 0) ? false:true); } template <typename T> bool AvlTree<T>::insert(const T &t) { return insert(t,root); } template <typename T> bool AvlTree<T>::insert(const T &t, node *&n) { bool re = false; if (n == 0) { n = new node(t); re = true; } else { if (t < n->data) { re = insert(t,n->lc);//插入到左子樹 if (height(n->lc) - height(n->rc) == 2) {//子樹高度差超過1 if (t < n->lc->data) {//插入的值小於左子樹的值,說明還要插在左子樹的左子樹 LL(n);//作LL旋轉 } else { LR(n);//作LR旋轉 } } } else { re = insert(t,n->rc); if (height(n->rc) - height(n->lc) == 2) { if (t < n->rc->data) { RL(n); } else { RR(n); } } } } n->height = max(height(n->lc),height(n->rc)) + 1; return re; } template <typename T> void AvlTree<T>::remove(const T &t) { remove(t,root); } template <typename T> /** * @brief AvlTree<T>::remove * @param t * @param n * @return * 只討論左子樹,右子樹狀況對稱,刪除的節點都在P的左子樹上 * 1.P節點平衡因子爲0,刪除節點x,使其某棵子樹變矮,p的平衡因子變爲-1或1,樹的高度不變,整棵樹也不變 * 2.P節點平衡因子爲-1或1,刪除P較高子樹的節點,P平衡因子爲0,樹高發生了變化,須要繼續向上規格 * 3.P節點平衡因子爲-1或1,刪除P較矮子樹的節點,P不平橫,須要規格,樹高若是變化,須要繼續向上規格 * 3.1P的右子樹的平衡因子爲0,作RR,子樹高度不變,不準要規格 * 3.2P的右子樹的平衡因子與P相同,作一個RR,子樹高度變化,須要繼續規格 * 3.2P的右子樹的平衡因子與P相反,RL,子樹高度變化,須要貴徐規格 */ bool AvlTree<T>::remove(const T &t, node *&n) { bool re = true;//是否須要規格 TreeType flag;//標識是左子樹仍是右子樹 if (n == 0) { re = false; } else { if (t < n->data) { re = remove(t,n->lc); flag = LEFT; } else { if (t > n->data) { re = remove(t,n->rc); flag = RIGHT; } else { //t = n->data if (n->lc != 0 && n->rc != 0) { node *p = n->rc; while (p->lc != 0) p = p->lc; n->data = p->data; re = remove(p->data,n->rc); flag = RIGHT; } else { node *p = n; n = (n->rc == 0) ? n->lc : n->rc; delete p; re = false; } } } } if (re) { int t; switch (flag) { case LEFT://左子樹 t = height(n->lc) + 1 - height(n->rc);//左子樹刪除一個節點,如今的+1原來的 if (t == 0) {// re = false; } else { if (re == 1) {//說明左子樹較高 re = true; } else { int t2 = height(n->rc->lc) - height(n->rc->rc); switch (t2) { case 0: RR(n); re = false; break; case -1://左子樹矮,連個平衡因子相同,爲-1 RR(n); re = true; break; default: RL(n); re = true; break; } } } break; case RIGHT://右子樹 t = height(n->lc) - (height(n->rc)+1);//右子樹刪除一個節點,如今的+1原來的 if (t == 0) {// re = false; } else { if (re == -1) {//說明右子樹較高 re = true; } else {//較矮的樹 int t2 = height(n->lc->lc) - height(n->lc->rc); switch (t2) { case 0: LL(n); re = false; break; case 1://右子樹矮,連個平衡因子相同,爲1 LL(n); re = true; break; default: LR(n); re = true; break; } } } break; default: break; } } return re; } template <typename T> void AvlTree<T>::levelTraverse(std::ostream &os) const { LinkQueue<node*> queue; queue.enqueue(root); while(!queue.isEmpty()) { node *t = queue.dequeue(); if (t != NULL) { os << t->data << " "; queue.enqueue(t->lc); queue.enqueue(t->rc); } } } #endif // AVLTREE_HPP #include "avlTree.hpp" int main() { AvlTree<int> avlt; int arr[]={3,5,6}; for(int i = 0;i < 3;++i) { avlt.insert(arr[i]); } avlt.levelTraverse(); avlt.insert(2); std::cout << '\n'; avlt.levelTraverse(); avlt.insert(1); std::cout << '\n'; avlt.levelTraverse(); avlt.insert(4); std::cout << '\n'; avlt.levelTraverse(); }