1、AVL樹
創(chuàng)新互聯(lián)建站是一家以網(wǎng)絡(luò)技術(shù)公司,為中小企業(yè)提供網(wǎng)站維護(hù)、成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、網(wǎng)站備案、服務(wù)器租用、域名申請、軟件開發(fā)、微信平臺(tái)小程序開發(fā)等企業(yè)互聯(lián)網(wǎng)相關(guān)業(yè)務(wù),是一家有著豐富的互聯(lián)網(wǎng)運(yùn)營推廣經(jīng)驗(yàn)的科技公司,有著多年的網(wǎng)站建站經(jīng)驗(yàn),致力于幫助中小企業(yè)在互聯(lián)網(wǎng)讓打出自已的品牌和口碑,讓企業(yè)在互聯(lián)網(wǎng)上打開一個(gè)面向全國乃至全球的業(yè)務(wù)窗口:建站溝通電話:18982081108
AVL樹首先是一顆二叉搜索樹,滿足其所有性質(zhì),AVL樹又叫做高度平衡的二叉搜索樹;
AVL: 動(dòng)態(tài)搜索樹;
平衡因子bf: 右樹高度 — 左樹高度; bf的取值只能是1, 0, -1;
左右子樹都得符合平衡因子, 若不符, 的通過旋轉(zhuǎn)來調(diào)整平衡因子;
2、四種旋轉(zhuǎn)
(1)、單旋轉(zhuǎn)---->直線型
(2)、雙旋轉(zhuǎn)----->折線型
要進(jìn)行兩次旋轉(zhuǎn)的調(diào)整,判斷折線,看哪邊突出(就是三個(gè)結(jié)點(diǎn)中有一個(gè)突出的方向),就先向哪邊旋轉(zhuǎn);
四種旋轉(zhuǎn),每次就只針對(duì)兩個(gè)結(jié)點(diǎn)(要進(jìn)行旋轉(zhuǎn)的2個(gè)結(jié)點(diǎn));然后將上面的分支掛到旋轉(zhuǎn)后的L/R上即可。
3、畫平衡樹
根據(jù)一組數(shù)字,畫出其AVL樹:16 3 7 11 9 26 18 14 15
畫AVL樹,首先其實(shí)是一顆搜索二叉樹; 按照其比左孩子大,比右孩子小畫就行; 有了平衡因子,不滿足時(shí)在旋轉(zhuǎn)調(diào)整即可。
畫法如下:
4、四種旋轉(zhuǎn)的實(shí)現(xiàn)
永遠(yuǎn)只考慮三層以內(nèi)結(jié)點(diǎn)的旋轉(zhuǎn);
C++實(shí)現(xiàn)其所有代碼:
(1)、右單旋
代碼如下(代碼中ptr代表的是要bf不為平衡處,指向要進(jìn)行旋轉(zhuǎn)的結(jié)點(diǎn)):
void RotateR(AVLNode*&ptr){ AVLNode *subR = ptr; ptr = ptr->leftChild; //通過引用直接修改指向1的指針(可能是上一個(gè)的左孩子/右孩子) subR->leftChild = ptr->rightChild; ptr->rightChild = subR; ptr->bf = subR->bf = 0; }
(2)、左單旋
左單旋與右單旋的代碼是鏡像的,并且想法是一致的; 所以代碼如下:
void RotateL(AVLNode*&ptr){ AVLNode *subL = ptr; ptr = subL->rightChild; //同樣是經(jīng)過引用修改 subL->rightChild = ptr->leftChild; ptr->leftChild = subL; subL->bf = ptr->bf = 0; }
在進(jìn)行單旋轉(zhuǎn)時(shí),因?yàn)槭窃诓迦?,其自身的bf不用調(diào)整,初始化為0;修改的是根和另一個(gè)結(jié)點(diǎn)的bf;
(3)、先左后右單旋
在進(jìn)行雙旋轉(zhuǎn)時(shí),首先明確左/右孩子,根結(jié)點(diǎn)的最終情況, 在進(jìn)行調(diào)整;并且在雙旋轉(zhuǎn)時(shí)每個(gè)結(jié)點(diǎn)的bf都得改變;
平衡因子在這不好考慮,有點(diǎn)復(fù)雜,具體分析如下:
平衡因子的考慮關(guān)鍵在:ptr有左樹/右樹,對(duì)應(yīng)上去則subL/sunR原先必有一個(gè)分支結(jié)點(diǎn); ptr沒有孩子結(jié)點(diǎn),對(duì)應(yīng)subR/subL原先也沒有分支結(jié)點(diǎn);
代碼如下:
void RotateLR(AVLNode*&ptr){ AVLNode *subR = ptr; //最終右孩子 AVLNode *subL = ptr->leftChild; //最終左孩子 ptr = subL->rightChild; //最終根節(jié)點(diǎn),因?yàn)橐?最終這個(gè)修改了指向根結(jié)點(diǎn),完成了連接; subL->rightChild = ptr->leftChild; ptr->leftChild = subL; if(ptr->bf <= 0){ subL->bf = 0; //此時(shí)的情況就是,自己ptr原先沒有掛結(jié)點(diǎn)或者是左樹掛上結(jié)點(diǎn),而滿足這種情況下,sunL原先必有左樹,此時(shí)在掛上右樹,所以為0; }else{ subL->bf = -1; //此時(shí)的情況是ptr有右孩子,而sunL有左孩子,滿足這種情況,所以bf只能是-1; } subR->leftChild = ptr->rightChild; ptr->rightChild = subR; if(ptr->bf == -1){ //當(dāng)結(jié)點(diǎn)ptr其只有左孩子時(shí), subR->bf = 1; //sunR必定有右孩子,所以此時(shí)為1 }else{ subR->bf = 0; //當(dāng)ptr沒有孩子結(jié)點(diǎn)或有一個(gè)右孩子時(shí)(此時(shí)subR必有右樹),所以此時(shí)為0; } ptr->bf = 0; //調(diào)整后根的bf永遠(yuǎn)是0; }
(4)、先右后左單旋
與上一個(gè)雙旋的代碼是鏡像的, 并且想法是一致的; 平衡因子的修改有點(diǎn)不一樣,注意一下就行, 所以代碼如下:
void RotateRL(AVLNode*&ptr){ AVLNode *subL = ptr; AVLNode *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; }