您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關數據結構中的AVL樹是什么意思,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
1、AVL樹簡介
AVL樹本質上還是一棵二叉搜索樹,又稱高度平衡的二叉搜索樹。它能保持二叉樹的高度平衡,盡量降低二叉樹的高度,減少樹的平均搜索長度。對于二叉搜索樹的介紹和實現,可查看本人上一篇博客。
2、AVL樹的特點
1)本身首先是一棵二叉搜索樹。
2)帶有平衡條件:每個結點的左右子樹的高度之差的絕對值(平衡因子)最多為1。
3)樹中的每個左子樹和右子樹都是AVL樹。
4)每個結點都有一個平衡因子,任一結點的平衡因子是-1,0,1.
注:結點的平衡因子 = 右子樹高度 - 左子樹高度
3、AVL樹的效率
一棵AVL樹有N個結點,其高度可以保持在lgN,插入/刪除/查找的時間復雜度也是lgN。
AVL樹的復雜程度真是比二叉搜索樹高了整整一個數量級——它的原理并不難弄懂,但要把它用代碼實現出來還真的有點費腦筋。下面我們來看看AVL樹實現的接口,通過三叉鏈進行結點的實現。
template<class K, class V> struct AVLTreeNode//三叉鏈 { AVLTreeNode<K, V>* _left; AVLTreeNode<K, V>* _right; AVLTreeNode<K, V>* _parent; K _key; V _value; int _bf;//右子樹與左子樹的高度差 AVLTreeNode(const K& key = K(), const V& value = V())//加上K()和V(),可缺省構造 :_left(NULL) , _right(NULL) , _parent(NULL) , _key(key) , _value(value) , _bf(0) {} }; template<class K, class V> class AVLTree { typedef AVLTreeNode<K, V> Node; public: AVLTree() :_root(NULL) {} void Insert(const K& key, const V& value); Node* Find(const K& key); int Height(); bool IsBalance(); void PrintAVLTree(); private: Node* _Find(Node* root, const K& key); void _RotateL(Node*& parent); void _RotateR(Node*& parent); void _RotateLR(Node*& parent); void _RotateRL(Node*& parent); int _Height(Node* root); bool _IsBalance(Node* root); void _PrintAVLTree(Node* root); protected: Node* _root; };
下面對插入進行元素的分析:
1)判斷樹是否為空,為空時,新建根結點。
2)查找插入的key是否存在,存在就退出函數,不存在就執行3)。
3)找到插入key的位置,然后插入結點cur。
4)更新平衡因子:從cur開始向上其父結點進行更新平衡因子,如果結點的平衡因子不滿足AVL樹,進行旋轉調節平衡因子。
template<class K,class V> void AVLTree<K,V>::Insert(const K& key, const V& value) { if (_root == NULL) { _root = new Node(key, value); return; } if (Find(key))//存在key { return; } Node* prev = NULL; Node* cur = _root; while (cur)//插入key的位置cur { if (key < cur->_key) { prev = cur; cur = cur->_left; } else if (key > cur->_key) { prev = cur; cur = cur->_right; } } cur = new Node(key, value);//插如結點cur if (prev->_key > key) { prev->_left = cur; cur->_parent = prev; } else if (prev->_key < key) { prev->_right = cur; cur->_parent = prev; } //prev為cur的上一個結點,即為cur是prev的父親結點 prev = cur; cur = prev->_parent; while (cur) { //更新平衡因子:從插如的cur開始向上更新平衡因子 cur->_bf = _Height(cur->_right) - _Height(cur->_left); if (cur->_bf != -1 && cur->_bf != 1 && cur->_bf != 0)//不滿足AVL樹的結點,進行旋轉調節平衡因子 {//平衡因子為2時,一定存在右子樹;平衡因子為-2時,一定存在左子樹 //左單旋:2 1(平衡因子) if (cur->_bf == 2 && cur->_right->_bf == 1) { _RotateL(cur);//引用傳遞 } //右單旋:-2 -1 else if (cur->_bf == -2 && cur->_left->_bf == -1) { _RotateR(cur); } //左右旋轉:-2 1 else if (cur->_bf == -2 && cur->_left->_bf == 1) { _RotateLR(cur); } //右左旋轉:2 -1 else if (cur->_bf == 2 && cur->_right->_bf == -1) { _RotateRL(cur); } } prev = cur; cur = cur->_parent; } }
進行旋轉調節平衡因子,分四種情況:
(1)左單旋:cur的平衡因子為2,cur->_right的平衡因子為1。
(2)右單旋:cur的平衡因子為-2,cur->_left的平衡因子為-1。
(3)左右旋轉:cur的平衡因子為-2,cur->_left的平衡因子為1。
(4)右左旋轉:cur的平衡因子為-2,cur->_right的平衡因子為-1。
左右旋轉和右左旋轉可通過調用左單旋和右單旋進行,注意結束后重置平衡因子。
如果不是很清楚,可以自己畫圖進行分析。
左單旋:
template<class K, class V> void AVLTree<K, V>::_RotateL(Node*& parent) { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL;//1 subR->_parent = parent->_parent;//1 subR->_left = parent;//2 parent->_parent = subR;//2 if (subRL)//注意不為空,進行鏈接 subRL->_parent = parent; parent->_bf = subR->_bf = 0; //進行subR的父親結點和subR的鏈接 if (subR->_parent == NULL)//為空時,parent為根結點,更改根結點 _root = subR; else//不為空,進行鏈接 { if (subR->_parent->_key > subR->_key) subR->_parent->_left = subR; else subR->_parent->_right = subR; } parent = subR; }
右單旋:
template<class K, class V> void AVLTree<K, V>::_RotateR(Node*& parent) { Node* subL = parent->_left; Node* subLR = subL->_right; //不能變換順序 parent->_left = subL->_right;//1 subL->_parent = parent->_parent;//1 subL->_right = parent;//2 parent->_parent = subL;//2 if (subLR)//注意不為空,進行鏈接 subLR->_parent = parent; parent->_bf = subL->_bf = 0; //進行subL的父親結點和subL的鏈接 if (subL->_parent == NULL)//為空時,parent為根結點,更改根結點 _root = subL; else//不為空,進行鏈接 { if (subL->_parent->_key > subL->_key) subL->_parent->_left = subL; else subL->_parent->_right = subL; } parent = subL; }
左右旋轉:
template<class K, class V> void AVLTree<K, V>::_RotateLR(Node*& parent) { Node* pNode = parent;//需重新定義parent,在進行左右旋轉后,parent指向發生了變化 Node* subLNode = pNode->_left; Node* subLRNode = subLNode->_right; _RotateL(parent->_left); _RotateR(parent); //在單旋時,parent和subL的平衡因子都為0,在進行左右旋轉和右左旋轉會出錯,故重新設置平衡因子 //subLRNode的平衡因子存在三種情況:為0,為-1,為1。subLRNode的平衡因子影響parent和subL的平衡因子 if (subLRNode->_bf == 1) { pNode->_bf = 1; subLNode->_bf = 0; } else if (subLRNode->_bf == -1) { pNode->_bf = 0; subLNode->_bf = -1; } else { parent->_bf = 0; subLNode->_bf = 0; } }
右左旋轉:
template<class K, class V> void AVLTree<K, V>::_RotateRL(Node*& parent) { Node* pNode = parent; Node* subRNode = pNode->_right; Node* subRLNode = subRNode->_left; _RotateR(parent->_right); _RotateL(parent); if (subRLNode->_bf == 1) { pNode->_bf = -1; subRNode->_bf = 0; } else if (subRLNode->_bf == -1) { pNode->_bf = 0; subRNode->_bf = 1; } else { pNode->_bf = 0; subRNode->_bf = 0; } }
測試用例如下:
void AVLTreeTest() { AVLTree<int, int> avlt; //int arr[10] = { 16, 3, 7, 11, 9, 26, 18, 14, 15, 23 }; int arr[10] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 }; for (int i = 0; i < 10; ++i) { avlt.Insert(arr[i], i); avlt.PrintAVLTree(); } cout << avlt.IsBalance() << endl; }
看完上述內容,你們對數據結構中的AVL樹是什么意思有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。