(王道408考研数据结构)第五章树-第四节2:平衡二叉树(AVL)及其旋转
文章目錄
- 一:AVL樹(shù)基本概念
- 二:AVL樹(shù)實(shí)現(xiàn)原理
- (1)構(gòu)建AVL樹(shù)
- (2)構(gòu)建演示
- (3)旋轉(zhuǎn)方法
- A:右單旋轉(zhuǎn)調(diào)整(插入到較高左子樹(shù)左側(cè))
- B:左單旋轉(zhuǎn)調(diào)整(插入到較高右子樹(shù)右側(cè))
- C:先左后右雙旋轉(zhuǎn)調(diào)整(插入到較高左子樹(shù)右側(cè))
- D:先右后左雙旋轉(zhuǎn)調(diào)整(插入到較高右子樹(shù)左側(cè))
- 三:AVL樹(shù)相關(guān)代碼
一:AVL樹(shù)基本概念
二叉排序樹(shù)有一個(gè)缺陷:樹(shù)的高度會(huì)直接影響其查找效率,且樹(shù)越高效率越差,效率最差時(shí)為一棵單分支樹(shù)
平衡二叉樹(shù)(Self-Balancing Binary Search Tree):它首先是一顆二叉排序樹(shù),其中每個(gè)節(jié)點(diǎn)的左右子樹(shù)高度之差絕對(duì)值不超過(guò)1。將二叉樹(shù)上結(jié)點(diǎn)左子樹(shù)和右子樹(shù)高度之差的絕對(duì)值稱(chēng)之為平衡因子BF(Balance Factor),因此,平衡因子BF的取值只可能是-1、0和1中的一種
- -1:表示該結(jié)點(diǎn)左子樹(shù)高度小于右子樹(shù)高度
- 0:表示該結(jié)點(diǎn)左子樹(shù)高度等于右子樹(shù)高度
- 1:表示該結(jié)點(diǎn)左子樹(shù)高度大于右子樹(shù)高度
以下是一些例子
- ①是AVL樹(shù)
- ②不是AVL樹(shù),因?yàn)锳VL樹(shù)前提必須首先是二叉排序樹(shù)
- ③不是AVL樹(shù),因?yàn)榻Y(jié)點(diǎn)58左子樹(shù)高度為2,而右子樹(shù)為高度為0,BF>1
- ④是AVL樹(shù)
最小不平衡子樹(shù):距離插入點(diǎn)最近的,且平衡因子絕對(duì)值大于1的結(jié)點(diǎn)為根的子樹(shù)
如下,當(dāng)插入新節(jié)點(diǎn)37時(shí),距離它最近的平衡因子絕對(duì)值超過(guò)1的結(jié)點(diǎn)是58,所以58開(kāi)始以下的子樹(shù)為最小不平衡子樹(shù)
二:AVL樹(shù)實(shí)現(xiàn)原理
(1)構(gòu)建AVL樹(shù)
AVL樹(shù)構(gòu)建思想:在構(gòu)建二叉排序樹(shù)的過(guò)程中,每當(dāng)插入一個(gè)結(jié)點(diǎn)時(shí),先檢查該結(jié)點(diǎn)的插入是否導(dǎo)致了平衡性被破壞,若不是則繼續(xù)插入;若是則找出最小不平衡子樹(shù),在保持二叉排序樹(shù)特性的前提下,調(diào)整最小不平衡子樹(shù)中各結(jié)點(diǎn)的鏈接關(guān)系,也即平衡調(diào)整,進(jìn)行相應(yīng)的旋轉(zhuǎn),使之成為新的平衡子樹(shù)
int arr[10]={3,2,1,4,5,6,7,10,9,8}假設(shè)上面數(shù)組需要構(gòu)建為AVL樹(shù),由于AVL樹(shù)首先是BST樹(shù),所以會(huì)構(gòu)建成下面這樣
但是我們知道,BST樹(shù)很忌諱其高度太高,所以如果能調(diào)整為下面這樣那再合適不過(guò)了,因?yàn)橄旅娴臉?shù)依然是一棵BST樹(shù),但是其高度小了很多,查找效率自然也會(huì)得到提高
因此對(duì)于AVL樹(shù)的研究重點(diǎn)就在于如何調(diào)整,也就是如何旋轉(zhuǎn)
(2)構(gòu)建演示
對(duì)于333和222,構(gòu)建時(shí)沒(méi)有任何問(wèn)題
來(lái)到111并將其插入后,發(fā)現(xiàn)根節(jié)點(diǎn)333的平衡因子變?yōu)榱?,此時(shí)整棵樹(shù)成為最小不平衡子樹(shù),需要進(jìn)行調(diào)整:右單旋轉(zhuǎn)調(diào)整(點(diǎn)擊跳轉(zhuǎn)查看)
- 因?yàn)榇藭r(shí)結(jié)點(diǎn)插入到了較高左樹(shù)左側(cè)
- 調(diào)整后,222成為了根節(jié)點(diǎn),333成為了222的右孩子,此樹(shù)高度平衡
接著結(jié)點(diǎn)444到來(lái),平衡因子沒(méi)有變化
接著結(jié)點(diǎn)555到來(lái),結(jié)點(diǎn)333的平衡因子變?yōu)?2,需要進(jìn)行調(diào)整:左單旋轉(zhuǎn)調(diào)整(點(diǎn)擊跳轉(zhuǎn)查看)
-
因?yàn)榇藭r(shí)結(jié)點(diǎn)插入到了較高右樹(shù)右側(cè)
-
再次達(dá)到平衡
接著結(jié)點(diǎn)666到來(lái),此時(shí)根節(jié)點(diǎn)222的平衡因子變?yōu)榱?2,進(jìn)行調(diào)整 左單旋轉(zhuǎn)調(diào)整(點(diǎn)擊跳轉(zhuǎn)查看)
- 因?yàn)榇藭r(shí)結(jié)點(diǎn)插入到了較高右樹(shù)右側(cè)
結(jié)點(diǎn)777到來(lái),結(jié)點(diǎn)5的平衡因子變?yōu)榱?2,進(jìn)行調(diào)整 左單旋轉(zhuǎn)調(diào)整(點(diǎn)擊跳轉(zhuǎn)查看)
- 因?yàn)榇藭r(shí)結(jié)點(diǎn)插入到了較高右樹(shù)右側(cè)
結(jié)點(diǎn)101010到來(lái),結(jié)構(gòu)無(wú)變化
結(jié)點(diǎn)999到來(lái),此時(shí)結(jié)點(diǎn)777的BF變?yōu)榱?2,理應(yīng)進(jìn)行左單旋轉(zhuǎn)調(diào)整,但是由于此時(shí)新結(jié)點(diǎn)插入到了較高右樹(shù)左側(cè),故直接使用左單旋轉(zhuǎn)調(diào)整是不可以的。(具體原因跳轉(zhuǎn)過(guò)去會(huì)詳細(xì)解釋),需要進(jìn)行 先右后左雙旋轉(zhuǎn)調(diào)整(點(diǎn)擊跳轉(zhuǎn)查看)
- 很明顯999插入了777的右子樹(shù)左側(cè),故不能直接使用左單旋轉(zhuǎn)
- 故先對(duì)999和101010進(jìn)行右旋,再對(duì)777、999和101010進(jìn)行左旋
接著結(jié)點(diǎn)888插入,使結(jié)點(diǎn)666的BF變?yōu)榱?2,屬于插入到了較高右樹(shù)的左側(cè),故需要進(jìn)行 先右后左雙旋轉(zhuǎn)調(diào)整(點(diǎn)擊跳轉(zhuǎn)查看)
(3)旋轉(zhuǎn)方法
大家最頭疼的可能就是如何選擇旋轉(zhuǎn)方法了,總結(jié)如下,只需按照如下邏輯選擇即可
A:右單旋轉(zhuǎn)調(diào)整(插入到較高左子樹(shù)左側(cè))
下圖中為抽象樹(shù),三角形表示的樹(shù)為高度平衡的二叉樹(shù)排序樹(shù)。如下情況中,結(jié)點(diǎn)A的平衡因子絕對(duì)值為1,左子樹(shù)較高
此時(shí)來(lái)了一個(gè)新的結(jié)點(diǎn)恰好插入到了B結(jié)點(diǎn)的左樹(shù),導(dǎo)致A結(jié)點(diǎn)的平衡因子變?yōu)?,樹(shù)不平衡,需要進(jìn)行調(diào)整
調(diào)整時(shí):將結(jié)點(diǎn)A下移一個(gè)高度,B上移一個(gè)高度,然后把B的右子樹(shù)掛在A的左子樹(shù)處(這樣做可以保證二叉排序樹(shù)的特性)
B:左單旋轉(zhuǎn)調(diào)整(插入到較高右子樹(shù)右側(cè))
左單調(diào)整和右單調(diào)整情況恰好相反,調(diào)整時(shí)結(jié)點(diǎn)B上移,結(jié)點(diǎn)A下移,讓結(jié)點(diǎn)B的左子樹(shù)做結(jié)點(diǎn)A的右子樹(shù)
C:先左后右雙旋轉(zhuǎn)調(diào)整(插入到較高左子樹(shù)右側(cè))
在右單旋轉(zhuǎn)調(diào)整中,由于新的結(jié)點(diǎn)插入到了較高左子樹(shù)的左側(cè),所以調(diào)整后可以使樹(shù)平衡
但如果此時(shí)將新結(jié)點(diǎn)插入到較高左子樹(shù)的右側(cè)
此時(shí)如果繼續(xù)使用右單旋轉(zhuǎn)調(diào)整,你會(huì)發(fā)現(xiàn)怎么也調(diào)整不過(guò)去,依然不平衡
在這種情況下就要使用到雙旋轉(zhuǎn)調(diào)整了
我們先把較高左子樹(shù)的右子樹(shù)拆分一下,拆分為兩棵樹(shù)
大家會(huì)發(fā)現(xiàn)此時(shí)如果要在B的右側(cè)插入一個(gè)結(jié)點(diǎn)有兩個(gè)選擇——要么插入到C的左側(cè),要么插入到C的右側(cè)
這里我以插入到C的右側(cè)為例
接著進(jìn)行雙旋轉(zhuǎn)調(diào)整:先對(duì)B樹(shù)進(jìn)行左單旋轉(zhuǎn)
形成了這樣一顆樹(shù)
然后對(duì)這顆樹(shù)再進(jìn)行右單旋轉(zhuǎn)調(diào)整,樹(shù)就平衡了
- 本例是插入到了C的右側(cè),如果插入到了C的左側(cè),調(diào)整也是一樣的
D:先右后左雙旋轉(zhuǎn)調(diào)整(插入到較高右子樹(shù)左側(cè))
- 特別注意:先看C部分再看本部分,C部分中解釋較為詳細(xì),本部分只是邏輯相反
在左單旋轉(zhuǎn)調(diào)整中,面對(duì)的情況是新節(jié)點(diǎn)插入到了較高右子樹(shù)的右側(cè),而如果新節(jié)點(diǎn)插入到了較高右子樹(shù)的左側(cè),那么就要使用先右后左雙旋轉(zhuǎn)調(diào)整
所以在這種情況下,先對(duì)右子樹(shù)進(jìn)行右單旋轉(zhuǎn)調(diào)整,然后再進(jìn)行左單旋轉(zhuǎn)調(diào)整
三:AVL樹(shù)相關(guān)代碼
對(duì)于AVL樹(shù)考研數(shù)據(jù)結(jié)構(gòu)基本不涉及代碼,其旋轉(zhuǎn)過(guò)程邏輯并不難,只是需要多捋一捋。其代碼實(shí)現(xiàn)有很多值得注意的地方,且稍不留心就容易掉坑,有興趣的同學(xué)可以查看我的另一篇文章,其中代碼都是可以跑通的,用C++實(shí)現(xiàn)
點(diǎn)擊跳轉(zhuǎn)
總結(jié)
以上是生活随笔為你收集整理的(王道408考研数据结构)第五章树-第四节2:平衡二叉树(AVL)及其旋转的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 关于chm文件打不开的解决方案
- 下一篇: 服务器意外重启导致storm报错的问题处