前面學習二叉查找樹和二叉樹的各類遍歷,可是其查找效率不穩定(斜樹),而二叉平衡樹的用途更多。查找相比穩定不少。(歡迎關注數據結構專欄)java
容易保持
。並且要保證它的深度是O(logN).平衡因子
)不大於1;而且它的每一個子樹也都是平衡二叉樹。n0=0
;n1=1
;nk=n(k-1)+n(k-2)+1
;(求法能夠類比斐波那契!)難點:AVL是一顆二叉排序樹,用什麼樣的規則或者規律讓它可以在複雜度不過高的狀況下實現動態平衡呢?
node
若是簡單的以單節點看,大體有上面四種
情形,而且他們的最後結果也是有的有所相近。只是:上下會變更。該在左面的還在左面,改在右面的還在右面。
這只是針對在底部,對於可能出現的平衡要首先搞清楚:
因此針對四種不平衡,可能出如今底部,也可能出如今頭,也可能出如今某個中間節點致使不平衡。 而咱們只須要研究其首次不平衡點,解決以後整棵樹即繼續平衡。固然,在實際解決確定會帶上遞歸
的思想解決問題。算法
出現這種狀況的緣由是節點的右側的右側較深這時候不平衡節
點須要左旋
。再細看過程。後端
root(oldroot)
節點下沉,中間節點(newroot)
上浮.而其中中間節點(newroot)
的右側依然不變。根節點(oldroot)
(畢竟一棵樹)。可是這樣newroot
原來左側節點H
空缺。而咱們須要仍然讓整個樹完整而且知足二叉排序樹的規則。oldroot右側空缺
,恰好這個位置知足
在oldroot的右側。在newroot的左側。.因此咱們將H插入在這個位置。NULL
。不過不影響操做!private node getRRbanlance(node oldroot) {//右右深,須要左旋 // TODO Auto-generated method stub node newroot=oldroot.right; oldroot.right=newroot.left; newroot.left=oldroot; oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1; newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原來的root的高度須要重新計算 return newroot; }
而右旋和左旋相反,可是思路相同,根據上述進行替換便可!
代碼:數據結構
private node getLLbanlance(node oldroot) {//LL小,須要右旋轉 // TODO Auto-generated method stub node newroot=oldroot.left; oldroot.left=newroot.right; newroot.right=oldroot; oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1; newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原來的root的高度須要重新金酸 return newroot; }
產生不平衡的條件緣由是:學習
root節點右側左側節點的深度高些
,使得與左側的差大於1
.這個與咱們前面看到的左旋右旋不一樣的是由於它的結構不能直接變一下就能夠完成。下面在上面右側
)因此若是平衡的話,那麼右左的R.L
應該在中間,而R
應該在右側
。原來的root在左側。這種雙旋轉其實也很簡單。不要被外表唬住。基於前面的單旋轉,雙旋轉有兩種
具體邏輯思路
。
思路1:兩次旋轉RR,LL
根據上圖所圈的,先對底部使得底部的大小關係變化,使其在知足二叉平衡樹的條件下還知足RR結構的二叉樹。因此只須要對右節點R先進行右旋
,再對ROOT進行左旋便可。
思路2:直接分析
根據初始和結果的狀態,而後分析各個節點變化順序。手動操做這些節點便可!測試
ROOT,R,R.L
三個節點變化。R.L確定要在最頂層。左右分別指向ROOT和R。那麼這其中R.left,ROOT.right
發生變化(原來分別是R,L和R)暫時爲空。而恰好根據左右大小關係能夠補上R.L的左右節點
。private node getRLbanlance(node oldroot) {//右左深 // node newroot=oldroot.right.left; // oldroot.right.left=newroot.right; // newroot.right=oldroot.right; // oldroot.right=newroot.left; // newroot.left=oldroot; // oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1; // newroot.right.height=Math.max(getHeight(newroot.right.left),getHeight(newroot.right.right))+1; // newroot.height=Math.max(getHeight(oldroot.left),getHeight(newroot.right))+1;//原來的root的高度須要重新金酸 oldroot.right =getLLbanlance(oldroot.right); oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1; return getRRbanlance(oldroot); }
根據上述RL修改便可
.net
private node getLRbanlance(node oldroot) { oldroot.left =getRRbanlance(oldroot.left); oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1; return getLLbanlance(oldroot); }
height
屬性。用於計算高度(平衡因子)插入是遞歸插入。遞歸一個來回的過程,去的過程進行插入。回的過程進行高度更新。和檢查是否平衡。不要寫全局遞歸計算高度,效率過低下。事實上高度變化只和插入和平衡有關,仔細考慮即不會有疏漏!
code
可能有些疏漏
,若是有問題還請各位一塊兒探討
!刪除
等其餘操做,(原理類似。刪除後平衡)有興趣能夠一塊兒研究。若是對後端、爬蟲、數據結構算法
等感性趣歡迎關注個人我的公衆號交流:bigsai
(回覆數據結構、爬蟲、java等有精心準備資料一份!)
blog