AVL樹詳解與總結
前言:
什麼叫做AVL樹?
AVL樹的定義:
1、AVL的左右子樹高度之差的絕對值不超過1;
2、樹中的左右子樹都為AVL樹
3、平衡因子只能是(-1、0、1)
AVL樹的效率
AVL樹的總共節點為N個,他的高度能搞保持在logN,插入、刪除、查詢等操作的時間複雜度也是logN。
AVL樹的實現:
1、AVL樹的插入:
思路分析:1> 既然是插入就需要先找到插入的位置,使用while迴圈遍歷找到插入位置
2> 找到插入位置以後直接插入,然後向上遍歷修改父節點的平衡因子,當修改完以後的平衡因子有等於2或者-2的挑出來,進行樹的旋轉,並且調整平衡因子,使滿足AVL樹的定義。
3> 旋轉過程中需要考慮是左旋轉、右旋轉、左右旋轉、還是右左旋轉。左右旋轉簡單,直接呼叫自己編寫的左右旋轉函式即可,只要傳過來的節點記得加上引用就行了,這樣能夠直接連線到旋轉後的子樹。重點在於左右和右左旋轉,我們是否能直接呼叫左旋轉函式和右旋轉函式各一次?答案是否定的,因為在旋轉的過程中,不是在插入的那個位置進行旋轉,而是在中間進行旋轉,這是後父親節點和祖父節點的平衡因子BF就需要自己手動來定義了。以右左旋轉來分析:
如果當前節點的平衡因子為-1,那麼他的parent應該為1,pparent應該為0;
如果當前節點的平衡因子為1,那麼他的parent應該為0,pparent應該為-1;
如果當前節點的平衡因子為0,那麼他的parent應該為0,pparent應該為0;
具體自己下去畫個圖,在插入節點的位置(cur)下面加一個左節點或者右節點,然後分析。
#ifndef __BALANCETREE_H__ #define __BALANCETREE_H__ template<class K,class V> struct BLNode { K _key; V _value; BLNode<K, V>* _left; BLNode<K, V>* _right; BLNode<K, V>* _parent; int _bf; BLNode(const K& key, const V& value) :_key(key) , _value(value) , _parent(NULL) , _left(NULL) , _right(NULL) , _bf(0) {} }; template<class K,class V> class BalanceTree { typedef BLNode<K, V> Node; public: BalanceTree() :_root(NULL) {} bool Insert(const K& key, const V& value) { //先查詢需要插入的位置 if (_root == NULL) { _root = new Node(key, value); return true; } Node* parent = NULL; Node* cur = _root; while (cur) { if (cur->_key > key) { parent = cur; cur = cur->_left; } else if (cur->_key < key) { parent = cur; cur = cur->_right; } else { return false; } } //找到插入位置以後,確定平衡因子 Node* ppNode = parent->_parent; if (parent->_key > key)//找到插入位置以後判斷是在父節點的左邊還是右邊,插入以後先調整平衡因子,向上遍歷,如果本來是-1或者1插入以後為0就不用調整了,因為上一層看到的還是這一層的高度沒有變 { cur = new Node(key, value); parent->_left = cur; cur->_parent = parent; parent->_bf--; while (parent) { if ((parent->_bf == -1 ||parent->_bf ==1)&& parent->_parent != NULL) { if (parent->_parent->_key >parent->_key) parent->_parent->_bf--; else if (parent->_parent->_key < parent->_key) parent->_parent->_bf++; if (parent->_parent->_bf == 2 || parent->_parent->_bf == -2) break; cur = parent; parent = parent->_parent; } else break; } } else if (parent->_key < key) { cur = new Node(key, value); parent->_right = cur; cur->_parent = parent; parent->_bf++; while (parent) { if ((parent->_bf == 1 ||parent->_bf == -1)&& parent->_parent != NULL) { if (parent->_parent->_key >parent->_key) parent->_parent->_bf--; else if (parent->_parent->_key < parent->_key) parent->_parent->_bf++; if (parent->_parent->_bf == 2 || parent->_parent->_bf == -2) break; cur = parent; parent = parent->_parent; } else break; } } //根據平衡因子的變動,開始調整當前的樹,因為剛剛是平衡因子不符合的時候跳出來的 ppNode = parent->_parent; Node* pppNode = NULL; if (ppNode!=NULL) pppNode = ppNode->_parent; if (ppNode && (ppNode->_bf == 2 || ppNode->_bf == -2)) { //左旋 if (parent == ppNode->_right && parent->_right == cur) { RotateL(ppNode); } //右旋 else if (ppNode->_left == parent && parent->_left == cur) { RotateR(ppNode); } //左右雙旋 else if (ppNode->_left == parent &&parent->_right == cur) { int bf = cur->_bf; Node* pNode = ppNode; Node* pLeftNode = parent; RotateL(parent);//先左旋,再連結 ppNode->_left = parent; RotateR(ppNode); if (bf == 0) { pNode->_bf = 0; pLeftNode->_bf = 0; } else if (bf == -1) { pNode->_bf = 1; pLeftNode->_bf = 0; } else if (bf == 1) { pNode->_bf = 0; pLeftNode->_bf = -1; } } //右左雙旋 else if (ppNode->_right == parent &&parent->_left == cur) { int bf = cur->_bf; Node* pNode = ppNode; Node* pRightNode = parent; RotateR(parent); ppNode->_right = parent; RotateL(ppNode); if (bf == 0) { pNode->_bf = 0; pRightNode->_bf = 0; } else if (bf == -1) { pNode->_bf = 0; pRightNode->_bf = 1; } else if (bf == 1) { pNode->_bf = -1; pRightNode->_bf = 0; } } if (pppNode == NULL) { _root = ppNode; } else { if (pppNode->_key > ppNode->_key) pppNode->_left = ppNode; else if (pppNode->_key < ppNode->_key) pppNode->_right = ppNode; } } } size_t Height() { return _Height(_root); } void InOrder() { _InOrder(_root); cout << endl; } protected: size_t _Height(Node* root) { if (root == NULL) return 0; return _Height(root->_left) > _Height(root->_right) ? _Height(root->_left) + 1 : _Height(root->_right) + 1; } void _InOrder(Node* root) { if (root == NULL) return; _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } void rotateL(Node*& parent) { Node* subR = parent->_right; Node* subRL = subR->_left; subR->_parent = parent->_parent; subR->_left = parent; parent->_parent = subR; parent->_right = subRL; if (subRL != NULL) subRL->_parent = parent; parent->_bf = 0; subR->_bf = 0; parent = subR; } void RotateL(Node*& parent) { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; if (subRL != NULL) subRL->_parent = parent; subR->_parent = parent->_parent; parent->_parent = subR; subR->_left = parent; parent->_bf = 0; subR->_bf = 0; parent = subR; } void RotateR(Node*& parent) { Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR != NULL) subLR->_parent = parent; subL->_parent = parent->_parent; subL->_right = parent; parent->_parent = subL; parent->_bf = 0; subL->_bf = 0; parent = subL; } protected: Node* _root; }; void test() { BalanceTree<int, int> bt; int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 }; for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { bt.Insert(arr[i], i); } bt.InOrder(); cout << bt.Height() << endl; BalanceTree<int, int> bt1; int arr1[] = { 4,2,6,1,3,5,15,7,16,14 }; for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++) { bt1.Insert(arr1[i], i); } bt1.InOrder(); cout << bt1.Height() << endl; } #endif //__BALANCETREE_H__
2、AVL樹的刪除:
刪除相對而言跟插入差不多,都是需要理解過程的,對於刪除,我們只需要先找到要刪除的位置,然後分為三種情況:
1.左為空-------->直接連線到父節點上,只是需要判斷連線到父節點的左還是右上
2.右為空-------->同上
3.左右都不為空:找到右邊子樹的最左節點,(這裡還分為兩種情況:沒有左子節點和有)這裡只分析有左子節點的了,一直往左遍歷找到左子節點,交換左子節點和要刪除的節點,然後將parent->left連到左子節點的右就行了,最後一步就是調節平衡因子了,從當前節點開始向上修改平衡因子,以及判斷平衡因子有沒有為2或者-2的情況,然後跟上面一樣做處理。