数据结构与算法--面试必问AVL树原理及实现
數(shù)據(jù)結(jié)構(gòu)與算法–AVL樹(shù)原理及實(shí)現(xiàn)
- AVL(Adelson-Velskii 和landis)樹(shù)是帶有平衡條件的二叉查找樹(shù),這個(gè)平衡條件必須容易實(shí)現(xiàn),并且保證樹(shù)的深度必須是O(logN)。因此我們讓一棵AVL樹(shù)中每個(gè)節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)的高度最多相差1(空樹(shù)高度定義-1)如下圖,左邊是AVL樹(shù),右邊不是AVL樹(shù)。
- 左圖中3 節(jié)點(diǎn)左子樹(shù)高度0,右子樹(shù)高度1,相差不超過(guò)1。
- 右圖中節(jié)點(diǎn)3,左子樹(shù)蓋度0,右子樹(shù)高度2,相差超過(guò)1,不滿(mǎn)足AVL數(shù)要求。
- 我們可以在每一個(gè)節(jié)點(diǎn)中保留高度信息,那我們可以推算出如下 高度h 與節(jié)點(diǎn)之間關(guān)系的公式
- 在高度h的AVL樹(shù)中,最少節(jié)點(diǎn)數(shù)S(h)由S(h)=S(h-1)+S(h-2)+1標(biāo)識(shí)
- 對(duì)于h,S(h)=1; h=1, S(h)=2,明顯函數(shù)S(h)與斐波那契數(shù)列密切相關(guān),由此我們可以推算出AVL數(shù)的高度的界限1.44log(N+2)-1.328。
insert分析
-
經(jīng)過(guò)如上高度,限制條件分析,我們可以認(rèn)為,AVL樹(shù)操作都可以以時(shí)間O(logN)執(zhí)行。當(dāng)插入操作時(shí)候,我們需要更通向根節(jié)點(diǎn)路徑上那些節(jié)點(diǎn)的所有平衡信息,而插入操作比較棘手的地方子阿姨,一個(gè)插入節(jié)點(diǎn)可能破壞AVL的平衡性。
- 上圖中左圖插入數(shù)據(jù)5,變成右圖,平衡性改變,不符合AVL樹(shù)特性
-
因此我們需要考慮在insert之后恢復(fù)平衡性,這種操作總可以通過(guò)樹(shù)進(jìn)行簡(jiǎn)單的修正做到,我們成為旋轉(zhuǎn)。
-
我們將insert后必須重新平衡的節(jié)點(diǎn)記錄為a。由于任意節(jié)點(diǎn)最多兩個(gè)兒子,因此出現(xiàn)高度不平衡需要a的左右子樹(shù)的高度相差2,容易推出如下四種情況:
- 對(duì)a的左子樹(shù)的左子樹(shù)進(jìn)行一次insert
- 對(duì)a的左子樹(shù)的右子樹(shù)進(jìn)行一次insert
- 對(duì)a的右子樹(shù)的左子樹(shù)進(jìn)行一次insert
- 對(duì)a的右子樹(shù)的右子樹(shù)進(jìn)行一次insert
-
上面四點(diǎn)中 第一點(diǎn)與第四點(diǎn)鏡像對(duì)稱(chēng),第二點(diǎn)和第三點(diǎn)鏡像對(duì)稱(chēng),理論上我們只需要實(shí)現(xiàn)兩種就可以同樣的實(shí)現(xiàn)方法得出對(duì)稱(chēng)的方法。
-
第一種情況發(fā)生在外側(cè)情況(左左或者右右),該情況通過(guò)一次單旋轉(zhuǎn)可以完成跳轉(zhuǎn)。
-
第二中情況發(fā)生在內(nèi)部(左右或者右左),這種情況需要復(fù)雜一些的雙旋轉(zhuǎn)。
單旋轉(zhuǎn)
- 如上圖左圖中的樹(shù)節(jié)點(diǎn)4不滿(mǎn)足AVL樹(shù),因?yàn)樗淖笞訕?shù)的深度比右子樹(shù)深2層,改圖中描述的情況是第一點(diǎn)1中描述的情況。在插入2 節(jié)點(diǎn)之后,原來(lái)滿(mǎn)足AVL數(shù)的性質(zhì)遭到了破壞,子樹(shù) 3多出了一層我們需要調(diào)整節(jié)點(diǎn)然他在平衡。
- 我們將3節(jié)點(diǎn)上移,并且將4節(jié)點(diǎn)下移,得到右圖中所示的新的樹(shù)滿(mǎn)足AVL特性
- 我們可以形象的將樹(shù)看成是柔軟的,抓住3 節(jié)點(diǎn)向上提在重力的作用下3節(jié)點(diǎn)變成了新的根節(jié)點(diǎn)(子樹(shù)的根)。由于二叉查找樹(shù)的特性,4>3,
- 所以4節(jié)點(diǎn)變成了3節(jié)點(diǎn)的右節(jié)點(diǎn)。
- 如果3 有右節(jié)點(diǎn)x,那么3的右節(jié)點(diǎn)應(yīng)該變成4的左節(jié)點(diǎn),因?yàn)閤>3 并且x<4
- 2的左右節(jié)點(diǎn)不變,4的右節(jié)點(diǎn)不變
-我們?cè)趤?lái)插入一個(gè)數(shù)據(jù)1 ,得出如下結(jié)果:
- 如上左圖我們插入1 后,破壞了5 根節(jié)點(diǎn)的平衡性,5節(jié)點(diǎn)的左子樹(shù)深度3, 右子樹(shù)深度1,超過(guò)2,因此我們應(yīng)該在3 節(jié)點(diǎn)處進(jìn)行如上步驟的操作得到最終的AVL數(shù)右圖:
- 3節(jié)點(diǎn)編程根節(jié)點(diǎn),5節(jié)點(diǎn)編程3的右節(jié)點(diǎn)
- 3的右節(jié)點(diǎn)交給5的左節(jié)點(diǎn)
- 其他節(jié)點(diǎn)不變
雙旋轉(zhuǎn)
-
上面案例中的算法小時(shí),在下圖找那個(gè)是無(wú)效的:
-
如上左圖到右圖的變化,9節(jié)點(diǎn)在插入 7 節(jié)點(diǎn)后,時(shí)序平衡性,我們?cè)?與9節(jié)點(diǎn)之間作旋轉(zhuǎn),按上面描述的算法,得到右圖,還是非AVL數(shù)
-
我們通過(guò)如上的實(shí)驗(yàn)得出5 和9 之間的旋轉(zhuǎn)無(wú)法解決問(wèn)題。也就是5, 9 作為根都無(wú)法得到一個(gè)平衡樹(shù),那么只能由6 節(jié)點(diǎn)作為跟節(jié)點(diǎn)
-
如此的話(huà),節(jié)點(diǎn)的順序就一目了然了: 5節(jié)點(diǎn)是6左子樹(shù),9 是右子樹(shù),7 變?yōu)? 的左子樹(shù)。得到如下結(jié)果:
- 我們繼續(xù)接著上面的案例插入 15, 14,13。插入13容易,因?yàn)樗粫?huì)破壞節(jié)點(diǎn)的平衡性,但是插入12 之后硬氣10 節(jié)點(diǎn)的高度不平衡,這個(gè)屬于上面描述的情況3 的案例:需要通過(guò)一次右-左雙旋來(lái)解決這個(gè)問(wèn)題。
- 如上左圖中,右-左旋流程:
- 我們先在15 節(jié)點(diǎn)和14節(jié)點(diǎn)之間做一次右旋轉(zhuǎn),我們?cè)谧鲞@次右旋轉(zhuǎn)流程時(shí)候,假設(shè)14節(jié)點(diǎn)左節(jié)點(diǎn)還有一個(gè)節(jié)點(diǎn)是我們假設(shè)的虛擬節(jié)點(diǎn)
- 那么此時(shí)15 節(jié)點(diǎn)就滿(mǎn)足上述情況中的第一點(diǎn)左 左描述情況,那么我們用右旋得到如下圖情況:
- 如上圖我們完成了第一次右邊選擇,圖中虛線(xiàn)表示虛擬節(jié)點(diǎn)不存在
- 那么我們?cè)倏创藭r(shí)10 節(jié)點(diǎn)也是不符合平衡性質(zhì),而且恰好此時(shí)滿(mǎn)足第四點(diǎn)情況描述的右右的描述
- 那么我們按照之前的算法描述需要對(duì)10,14 節(jié)點(diǎn)之間進(jìn)行左旋得到如下結(jié)果
總結(jié)
- 至此我們對(duì)上面兩種旋轉(zhuǎn)做一個(gè)總結(jié),為了將項(xiàng)X的一個(gè)新節(jié)點(diǎn)插入到一個(gè)AVL樹(shù)中,
- 我們遞歸的將X插入到T數(shù)對(duì)應(yīng)的子樹(shù)位置,記錄改子樹(shù)為T(mén)_lr
- 如果T_lr的高度不變那么插入完成
- 如果T中出現(xiàn)高度不平衡,則根據(jù)X以及T和T_lr中項(xiàng)做適當(dāng)?shù)膯涡蛘唠p旋來(lái)更新這些高度
- 解決旋轉(zhuǎn)之后其他節(jié)點(diǎn)的歸屬問(wèn)題
- 經(jīng)過(guò)如上分析,我們給出以下實(shí)現(xiàn)(二叉查找樹(shù)上一節(jié)已經(jīng)實(shí)現(xiàn),在此基礎(chǔ)上進(jìn)行修改):
算法實(shí)現(xiàn)
- 節(jié)點(diǎn)定義,還是和上一節(jié)二叉查找樹(shù)中類(lèi)似,只不過(guò)我們?cè)诠?jié)點(diǎn)中需要維護(hù)一個(gè)高度信息,并且修改了comparable方法。如下實(shí)現(xiàn):
- 單左旋,單右旋代碼實(shí)現(xiàn):
- 如上代碼實(shí)現(xiàn),用下圖說(shuō)明,6節(jié)點(diǎn)因?yàn)? 的插入破壞平衡性
- 我們?cè)?節(jié)點(diǎn)和5節(jié)點(diǎn)之前進(jìn)行選擇
- 5節(jié)點(diǎn)成為新根節(jié)點(diǎn)
- 6 節(jié)點(diǎn)成為5節(jié)點(diǎn)的右節(jié)點(diǎn)
- 5節(jié)點(diǎn)的右節(jié)點(diǎn)編程6節(jié)點(diǎn)的左節(jié)點(diǎn)
- 和如上左旋流程一樣,達(dá)到目的
- 雙左旋,雙右旋轉(zhuǎn)實(shí)現(xiàn):
-
雙旋的情況我們將他看出是兩段,兩段分別進(jìn)行單旋操作:
- 第一步,如下圖,有K2節(jié)點(diǎn)進(jìn)行右旋得到右圖中樹(shù)結(jié)構(gòu)
- 第一步,如下圖,有K2節(jié)點(diǎn)進(jìn)行右旋得到右圖中樹(shù)結(jié)構(gòu)
-
第二步,對(duì)k3進(jìn)行左旋
- 刪除操作,添加操作:添加操作破壞平衡性,之后在糾正,由于二叉查找樹(shù)的刪除比插入更加復(fù)雜,英雌AVL刪除也同樣,我們也可以和insert方法一樣,在insert之后在糾正平衡性,這樣就可以在二叉查找樹(shù)的基礎(chǔ)上進(jìn)行很簡(jiǎn)單的實(shí)現(xiàn):
- 平衡性糾正方法:
- 其他方法:
上一篇:數(shù)據(jù)結(jié)構(gòu)與算法–二叉查找樹(shù)實(shí)現(xiàn)原理
下一篇:數(shù)據(jù)結(jié)構(gòu)與算法–二叉堆(最大堆,最小堆)實(shí)現(xiàn)及原理
總結(jié)
以上是生活随笔為你收集整理的数据结构与算法--面试必问AVL树原理及实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何快速查看电脑保修状态如何查看电脑质保
- 下一篇: 数据结构与算法--B树原理及实现