天天看點

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

動畫 | 什麼是二分搜尋樹(二叉查找樹)?

二分搜尋樹屬性

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

二分搜尋樹的又名比較多,有的叫二叉排序樹,也有的叫二叉查找樹,或者有序二叉查找樹。是指一棵空樹或者具有下列性質的二叉樹:

1.若任意節點的左子樹不空,則左子樹所有節點的值均小于它根節點的值;

2.若任意節點的右子樹不空,則右子樹所有節點的值均大于它根節點的值;

3.任意節點的左、右子樹也分别為二叉查找樹;

4.沒有鍵值相等的節點。

它的查找、插入和删除的時間複雜度都等于樹高,期望值是O(logn),最壞時間複雜度是O(n),比如樹退化成線性表。

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

查找元素

二分搜尋樹是為了實作快速查找而生的,也支援快速添加和删除一個資料。如何查找某個元素首先跟根節點去做比較,如果相等的話就傳回;如果待查元素要比根節點小,就進行左子樹遞歸查找;如果待查元素要比根節點大,就進行右子樹的遞歸查找;如果查找到最後還沒有一個符合的元素,就傳回null。

遞歸查找

遞歸查找的方式有很多,有層序周遊、前序周遊、中序周遊和後序周遊。我這裡就舉後面三個周遊方式。

Code

如果代碼是下面這樣寫的,那它周遊過程是怎麼樣的?看下面動畫。

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

動畫:前序周遊

(響應讀者的建議,動畫不放BGM了二分搜尋樹(二叉查找樹)?

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?
查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?
查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

(響應讀者的建議,動畫不放BGM了)

動畫:前中後周遊

從上面動畫就發現,通過中序周遊得到的正好是一個升序序列。如果不考慮升序,後序周遊也能夠為二分搜尋樹早點釋放記憶體,早點減少棧的使用空間。

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

添加元素

對于二叉樹的添加和删除元素,使用連結清單存儲形式比較好操作的,如果使用數組形式存儲,删除某一個有子樹的元素會引發一系列的位置改變,涉及到交換元素的位置,性能也比連結清單的小。是以待會後面出現的僞代碼都以連結清單存儲形式去操作。

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

删除元素:删除最小和最大的元素

删除最小和最大的元素很簡單,如果是删除最小的元素,從二叉樹的頂點出發,一直遞歸它的左孩子,直到某節點的左孩子為空,這時候這個節點就是最小的元素。删除最大的元素也是一樣的,一直遞歸它的右孩子,直到某節點的右孩子為空。

删除任意元素

如果删除任意元素,而這元素正好有左右子樹的,那該是怎麼辦呢?

1962年,Hibbard提出了HibbardDeletion的解決方法。

看到Hibbard名字就想起來,我在

希爾排序

介紹過Hibbard增量序列,也把它相應的公式通過代碼展現出來,代替希爾增量序列去進行希爾排序,最壞時間複雜度也比希爾增量序列的要小。

回到删除有左右子樹的元素,想想它的左右子樹也屬于二叉排序樹(也是二分搜尋樹),它左子樹的最大值比它小,它右子樹的最小值比它大。是以不管選擇左子樹的最大值還是選擇右子樹的最小值,替換掉要删除的元素,整個二叉樹都是符合二分搜尋樹的規則。

動畫:删除元素

Code:删除任意元素

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

支援重複元素的二分搜尋樹

二分搜尋樹有一個規則是:沒有鍵值相等的節點。那麼就不建議把待添加的元素跳過值相等的節點,到下一步繼續比較直到插入新的節點。比如我想插入23,插完之後上有23,下有23,那查找就沒有意義了,也破壞了時間複雜度上的O(logn)。

建議就是在節點上加一個屬性:count。當插入23的時候,count就可以自算++。這不僅滿足了沒有鍵值相等的規則,也滿足時間複雜度的期望值。

查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?
查找類算法之二分搜尋樹 | 算法必看系列十動畫 | 什麼是二分搜尋樹(二叉查找樹)?

--END--

來源 | 算法無遺測

作者 | 我脫下短袖

繼續閱讀