先來了解一些基本概念:
1)什么是二叉平衡樹?
之前我們了解過二叉查找樹,我們說通常來講, 對於一棵有n個節點的二叉查找樹,查詢一個節點的時間復雜度為log以2為底的N的對數。
通常來講是這樣的, 但是。。。有例外
比如,我們向一棵樹中輸入預先排好序的數據, 如1,2,3,4,5,。。。10000, 可以想象到,將形成一棵斜樹那么查找10000就要經過9999次比較才能得到,這顯然不是我們期望看到的
所以,我們希望引入一個約束條件----任何節點的深度不得過深。
這就是二叉平衡樹
二叉平衡樹是二叉查找樹(排序樹)的一種,其每一個節點的左子樹和右子樹的高度差最多為1
如上圖, 左邊兩棵樹並不是二叉平衡樹, 因為節點58的左子樹和右子樹高度差>1。 (分別為2和3)
2)平衡因子?
二叉樹上節點的左子樹高度 減去 右子樹高度, 得到的結果稱為該節點的平衡因子
3)最小不平衡樹?
當我們給一個二叉平衡樹增加新的節點時,會產生最小不平衡樹
以 距離插入節點最近的,平衡因子大於1的節點 為根的樹, 我們稱為最小不平衡樹
如
了解了基本概念之后,我們來看看如何構建一棵二叉平衡樹
來看一個例子,我們從初始的空AVL樹開始插入3,2,1, 當插入1時, AVL的性質在根(3)處被破壞,此時,我們需要在根與其左兒子間實施單旋轉以解決這個問題
我們繼續插入節點4, 這沒什么問題, 但當我們插入節點5時, AVL的性質在節點3處被破壞, 因此, 我們需要在節點3與其右兒子之間實施一次左旋來解決這個問題
現在我們再插入節點6,此時AVL的性質在根節點(2)處被破壞, 因此我們在根節點和其右節點4之間實施一次左旋
左旋的結果是 4成為根節點,2成為4的左兒子, 4 原本的左兒子3成為2的右兒子
現在再插入節點7, 此時AVL的性質在節點5處被破壞, 因此我們在5節點和其右節點6之間實施一次左旋
根據上面的操作,我們現總結處兩條規律:(太繞口,不用記,看圖能理解就可以)
假設當我們插入新節點時,導致了原AVL樹在節點 p 處不平衡,那么
1)如果添加的新節點是p的左兒子的左兒子, 則在p和其左兒子之間實施一次右旋轉, p變成其左兒子的右兒子(如果其左兒子原本已經有右兒子, 則原本的右兒子成為p的左兒子)
2)如果新加的節點是p的右兒子的右兒子, 則在p和其右兒子之間實施一次左旋轉,p變成其右兒子的左兒子(如果其右兒子原本已經有左兒子, 則原本的左兒子成為p的右兒子)
感覺頭都轉暈了😄
but...真正復雜的還在后面。。。。。。。。
現在我們給上面的二叉樹插入節點16,這沒什么問題, 再插入15, 此時二叉樹在節點7處不再平衡,這時我們發現單旋轉已經不能解決問題了, 如果只是在7和16之間左旋的話,15將成為16的右節點,這顯然不符合二叉排序樹的性質。
因此這里我們需要兩次旋轉,先在15和16之間進行一次右旋,右旋之后就滿足了上文規律2)的條件,此時再進行一次左旋
現在我們再插入14, 跟上面情況類似,插入之后需要執行先右旋再左旋的操作
現在讓我們再做個小結,
當我們插入新節點時,導致了原AVL樹在節點 p 處不平衡,那么
3)如果添加的新節點是p的右兒子的左兒子, 則先在其右兒子和右兒子的左兒子之間實施一次右旋轉, 再在p和其右兒子之間實施一次左旋轉
3)如果添加的新節點是p的左兒子的右兒子, 則先在其左兒子和左兒子的右兒子之間實施一次左旋轉, 再在p和其左兒子之間實施一次右旋轉
再高度總結下: 同向時單旋轉,異向時雙旋轉
原理就到這里了, 代碼實現比較復雜,這里就不再寫了,個人覺得沒有必要,因為AVL樹是最古老的平衡樹, 我們了解其原理是為了下一步----更好的理解紅黑樹。