搜尋二叉樹
定義:任何一個節點,左樹都比這個節點小,右數都比這個節點大,經典搜尋二叉樹是沒有重複值的,有重複值就壓在一起
構造搜尋二叉樹方法:
- 比節點大,就往右邊滑,滑到空就把節點加上
- 比節點小,就往左邊滑,滑到空就把節點加上
搜尋二叉樹的增刪改,注:改可以轉換成刪掉再增加
搜尋二叉樹的刪除流程如下
- 未找到,直接返回
- 如果找到,既沒有左孩子,也沒有右孩子,直接刪掉
- 如果找到,有右無左,右孩子提拔
- 如果找到,有左無右,左孩子提拔
- 如果找到,有左有右,則找右樹的最左節點(後繼節點)替代被刪除位置,後繼節點的右孩子直接給新的右樹最左節點。
搜尋二叉樹的刪除示例圖如下,假設原搜尋二叉樹是如下結構:
如果要刪除60號節點,因為60號節點既沒有左孩子,也沒有右孩子,所以直接刪除即可。
如果要刪除75號節點,因為75號節點只有左孩子,所以直接用75號節點的左孩子替代被刪除的75號節點位置即可。
如果要刪除71號節點,因為71號節點只有右孩子,所以直接用其右孩子替代即可。
如果要刪除的節點是70號節點,因為70號節點既有左孩子又有右孩子,所以,首先要找到70號節點的後繼節點(即71號位置)
然後用後繼節點替代被刪除節點的位置,同時,把後繼節點的右孩子給新的右側最左節點(即75號節點位置)
注意delete
方法在刪除的時候,需要考慮後繼節點是直接的右孩子還是距離需要刪除的節點有一定距離的節點!
搜尋二叉樹的最大問題是: 輸入狀況決定效能,如果輸入狀況比較好,樹是平衡的,輸入狀況比較差,樹不是平衡的,嚴格的平衡性指的是:任何一個節點左樹右樹高度差不超過1,比如使用者輸入的資料如下[1,2,3,4,5]
,形成的搜尋二叉樹就退化成了如下連結串列結構
所以需要引入自平衡的功能, 即平衡搜尋二叉樹
平衡搜尋二叉樹
平衡搜尋二叉樹要滿足如下兩種情況
- key按序組織
- 增刪改
O(logN)
AVL樹, SBT, 紅黑樹都是平衡搜尋二叉樹的一種具體實現,增刪改的時間複雜度均為O(logN)
平衡搜尋二叉樹在搜尋二叉樹的基礎上增加了兩個操作,左旋和右旋。
左旋和右旋要針對具體節點說
左旋示例,如下搜尋二叉樹,如果針對A節點左旋
如下搜尋二叉樹,如果針對A節點右旋
AVL樹,SBT,紅黑樹無論平衡性如何定義,底層的操作都是左旋和右旋。
AVL樹
AVL樹最嚴格的平衡性,左右高度只差絕對值小於2。
AVL樹的增刪節點和平衡二叉樹一樣,只是在呼叫增刪操作後,AVL樹有自己的調整策略。
AVL樹平衡性破壞有如下幾種型別
LL
解決辦法:只做一次右旋,示例:
RR同理,只做一次左旋即可。
LR
LR情況示例
先對B進行一次左旋
再對頭部A進行一次右旋
RL同理
LL+LR
對於既是LL,又是LR的情況,例如:
在這樣的情況下,一定要按照LL方式來調整。
如上例,調整規則為:
同理,對於既是RR,又是RL的情況,也要按照RR方式來調整。
AVL調整過程
在增加節點的時候,插入位置的父節點一直往上查,看下每個節點是否違規。
在刪除節點的時候,刪除位置的父節點一直往上查,看下每個節點是否違規,如果刪除節點包含左右孩子,那麼必須從這個節點的後繼節點往上一直查。
AVL實現程式碼
SBT
SBT全稱Size Balanced Tree,任何一個叔節點子樹節點數不少於他的侄子節點個數(叔侄關係如下示例圖),即左右樹節點數的規模差不多就是2倍加1
AVL樹維持的是每個節點的高度,而SBT維持的是每個節點子樹節點個數。
SBT的違規情況也有四種(LL,LR,RR,RL)
SBT的LL違規和調整過程
父的左孩子的左孩子的節點個數大於父親右孩子的節點數,例如:
所以,上述搜尋二叉樹在做完AVL調整後,為如下情況:
按AVL的方式呼叫完畢後,看誰的孩子發生了變化,如上例,是A和父兩個點的孩子發生變化,就遞迴呼叫m(A), m(父), LR, RR, RL調整方式一樣,都是通過AVL對應的調整方式,然後檢視是否有節點的孩子發生變化,如果發生變化,對這些節點做遞迴呼叫。
注:SBT在刪除節點的時候,不做平衡性調整,只在add節點的時候做平衡性調整,因為有遞迴行為。
SBT的實現程式碼
有序表的使用
【牛客】找工作問題
問題描述:NowCoder_FindJob
程式碼參考:NowCoder_FindJob
【LeetCode 218】天際線問題
問題描述: LeetCode_0218_TheSkylineProblem
程式碼參考:LeetCode_0218_TheSkylineProblem
【LeetCode 327】區間和的個數
問題描述:LeetCode_0327_CountOfRangeSum
程式碼參考:LeetCode_0327_CountOfRangeSum
注:本題既可以用改寫歸併排序的方法來解,也可以通過改寫有序表來解。
【LeetCode 480】滑動視窗的中位數
問題描述:LeetCode_0480_SlidingWindowMedian
程式碼參考:LeetCode_0480_SlidingWindowMedian