C++?AVL樹的兩單旋和兩雙旋的項目實踐
如果在一棵原本是平衡的AVL樹中插入一個新節(jié)點,可能造成不平衡,此時必須調(diào)整樹的結(jié)構(gòu),使之平衡化。根據(jù)節(jié)點插入位置的不同,AVL樹的旋轉(zhuǎn)分為四種。
1. 新節(jié)點插入較高左子樹的左側(cè)---左左:右單旋
a/b/c分別是高度為h的AVL子樹
上圖在插入前,AVL樹是平衡的,新節(jié)點插入到30的左子樹(注意:此處不是左孩子)中,30左子樹增加了一層,導(dǎo)致以60為根的二叉樹不平衡,要讓60平衡,只能將60左子樹的高度減少一層,右子樹增加一層,即將左子樹往上提,這樣60轉(zhuǎn)下來,因為60比30大,只能將其放在30的右子樹,而如果30有右子樹,右子樹根的值一定大于30,小于60,只能將其放在60的左子樹,旋轉(zhuǎn)完成后,更新節(jié)點的平衡因子即可。在旋轉(zhuǎn)過程中,有以下幾種情況需要考慮:
1. 30節(jié)點的右孩子可能存在,也可能不存在
2. 60可能是根節(jié)點,也可能是子樹
如果是根節(jié)點,旋轉(zhuǎn)完成后,要更新根節(jié)點
如果是子樹,可能是某個節(jié)點的左子樹,也可能是右子樹
代碼
//右單旋 void RotateR(Node* parent) { Node* SubL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR) { subL->_right = parent; } subL->_right = parent; Node* ppnode = parent->_parent; parent->_parent = subL; if (parent == _root) { _root = subL; subL->_parent = nullptr; } else { if (ppnode->_left == parent) { ppnode->_left = subL; } else { ppnode->_right = subL; } subL->_parent = ppnode; } parent->_bf = 0; subL->_bf = 0; }
2. 新節(jié)點插入較高右子樹的右側(cè)---右右:左單旋
左單旋與右單旋的操作類似,只有左右節(jié)點的區(qū)別
代碼
//左單旋 void RotateL(Node* parent) { Node* SubR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; if (subRL) { subR->_left = parent; } subR->_left = parent; Node* ppnode = parent->_parent; parent->_parent = subR; if (parent == _root) { _root = subR; subR->_parent = nullptr; } else { if (ppnode->_left == parent) { ppnode->_left = subR; } else { ppnode->_right = subR; } subR->_parent = ppnode; } parent->_bf = 0; subR->_bf = 0; }
3. 新節(jié)點插入較高左子樹的右側(cè)---左右:先左單旋再右單旋
參考30和60的相對位置,將雙旋變成單旋后再旋轉(zhuǎn),即:先對30進行左單旋,然后再對90進行右單旋,旋轉(zhuǎn)完成后再考慮平衡因子的更新。
代碼
//左右單旋 void RotateLR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; int bf = subLR->_bf; RotateL(parent->_left); RotateR(parent); if (bf == 1) { parent->_bf = 0; subL->_bf = 0; subLR->_bf = 1; } else if (bf == -1) { parent->_bf = 0; subL->_bf = -1; subLR->_bf = 0; } else if(bf==0) { parent->_bf = 0; subL->_bf = 0; subLR->_bf = 0; } else { assert(false); } }
4. 新節(jié)點插入較高右子樹的左側(cè)---右左:先右單旋再左單旋
代碼
//右左單旋 void RotateRL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; int bf = subRL->_bf; RotateR(parent->_right); RotateL(parent); if (bf == 1) { parent->_bf = 0; subR->_bf = 0; subRL->_bf = 1; } else if (bf == -1) { parent->_bf = 0; subR->_bf = -1; subRL->_bf = 0; } else if (bf == 0) { parent->_bf = 0; subR->_bf = 0; subRL->_bf = 0; } else { assert(false); } }
總結(jié):
假如以pParent為根的子樹不平衡,即pParent的平衡因子為2或者-2,分以下情況考慮:
1. pParent的平衡因子為2,說明pParent的右子樹高,設(shè)pParent的右子樹的根為pSubR。
當(dāng)pSubR的平衡因子為1時,執(zhí)行左單旋。
當(dāng)pSubR的平衡因子為-1時,執(zhí)行右左雙旋。
2. pParent的平衡因子為-2,說明pParent的左子樹高,設(shè)pParent的左子樹的根為pSubL。
當(dāng)pSubL的平衡因子為-1是,執(zhí)行右單旋。
當(dāng)pSubL的平衡因子為1時,執(zhí)行左右雙旋。
旋轉(zhuǎn)完成后,原pParent為根的子樹個高度降低,已經(jīng)平衡,不需要再向上更新。
到此這篇關(guān)于C++ AVL樹的兩單旋和兩雙旋的項目實踐的文章就介紹到這了,更多相關(guān)C++ AVL樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實現(xiàn)LeetCode(133.克隆無向圖)
這篇文章主要介紹了C++實現(xiàn)LeetCode(133.克隆無向圖),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07linux根據(jù)pid獲取進程名和獲取進程pid(c語言獲取pid)
status文件,第一行的Name即為進程名,C程序?qū)崿F(xiàn)根據(jù)PID獲取進程名和根據(jù)進程名獲取PID,大家參考使用吧2013-12-12C++ Custom Control控件向父窗體發(fā)送對應(yīng)的消息
這篇文章主要介紹了C++ Custom Control控件向父窗體發(fā)送對應(yīng)的消息的相關(guān)資料,需要的朋友可以參考下2015-06-06關(guān)于函數(shù)傳參問題(指針傳參,值傳參,引用傳參)
這篇文章主要介紹了關(guān)于函數(shù)傳參問題(指針傳參,值傳參,引用傳參),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01C語言基于循環(huán)鏈表解決約瑟夫環(huán)問題的方法示例
這篇文章主要介紹了C語言基于循環(huán)鏈表解決約瑟夫環(huán)問題的方法,簡單描述了約瑟夫環(huán)問題并結(jié)合實例形式分析了C語言使用循環(huán)鏈表解決約瑟夫環(huán)問題的具體操作技巧,需要的朋友可以參考下2018-01-01OpenCV數(shù)字圖像處理基于C++之圖像形態(tài)學(xué)處理詳解
OpenCV是一款由Intel公司俄羅斯團隊發(fā)起并參與和維護的一個計算機視覺處理開源軟件庫,支持與計算機視覺和機器學(xué)習(xí)相關(guān)的眾多算法,下面這篇文章主要給大家介紹了關(guān)于OpenCV數(shù)字圖像處理基于C++之圖像形態(tài)學(xué)處理的相關(guān)資料,需要的朋友可以參考下2022-12-12