二叉樹?
二叉樹(Binary Tree)是指每個節點最多只有兩個分支的樹結構(即不存在分支大於 2 的節點),如下圖所示:
這是一棵擁有 6 個節點深度為 2(深度從 0 開始),並且根節點為 3 的二叉樹。二叉樹的左右兩個分支通常被稱作“左子樹”和“右子樹”,而且這些分支左右次序不能隨意地顛倒。
二叉查找樹?
一棵空樹或者滿足以下性質的二叉樹被稱之為二叉查找樹(Binary Search Tree)也被稱為二叉搜索樹、有序二叉樹(Ordered Binary Tree)或排序二叉樹(Sorted Binary Tree)等。
(1)如果任意節點的左子樹不為空,並且左子樹上所有節點的值均小於它的根節點的值;
(2)如果任意節點的右子樹不為空,並且右子樹上所有節點的值均大於或等於它的根節點的值;
(3)任意節點的左、右子樹分別為二叉查找樹。
標准的二叉查找樹:
平衡樹?
所謂的平衡樹是指一種改進的二叉查找樹,顧名思義平衡樹就是將二叉查找樹平衡均勻地分布,這樣的好處就是可以減少二叉查找樹的深度。
一般情況下二叉查找樹的查詢復雜度取決於目標節點到樹根的距離(即深度),當節點的深度普遍較大時,查詢的平均復雜度就會上升,因此為了實現更高效的查詢就有了平衡樹。
非平衡二叉樹(左)和平衡二叉樹(右)如下圖所示:
可以看出使用平衡二叉樹可以有效的減少二叉樹的深度,從而提高了查詢的效率。
紅黑樹?
紅黑樹除了具備二叉查找樹的基本特性之外,還具備以下特性:
(1) 節點是紅色或黑色;
(2) 根節點是黑色;
(3) 所有葉子都是黑色的空節點(NIL 節點);
(4) 每個紅色節點必須有兩個黑色的子節點,也就是說從每個葉子到根的所有路徑上,不能有兩個連續的紅色節點;
(5) 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑色節點。
紅黑樹結構如下圖所示:
紅黑樹的優勢?
紅黑樹的優勢在於它是一個平衡二叉查找樹,對於普通的二叉查找樹(非平衡二叉查找樹)在極端情況下可能會退化為鏈表的結構,例如,當我們依次插入 3、4、5、6、7、8 這些數據時,二叉樹會退化為如下鏈表結構:
當二叉查找樹退化為鏈表數據結構后,再進行元素的添加、刪除以及查詢時,它的時間復雜度就會退化為 O(n);而如果使用紅黑樹的話,它就會將以上數據轉化為平衡二叉查找樹,這樣就可以更加高效的添加、刪除以及查詢數據了,這就是紅黑樹的優勢。紅黑樹的高度近似 log2n,它的添加、刪除以及查詢數據的時間復雜度為 O(logn)。
自平衡的紅黑樹
紅黑樹能夠實現自平衡和保持紅黑樹特征的主要手段是:變色、左旋和右旋。
左旋
左旋指的是圍繞某個節點向左旋轉,也就是逆時針旋轉某個節點,使得父節點被自己的右子節點所替代,如下圖所示:
在 TreeMap 源碼中左旋的實現源碼如下:
左旋代碼說明:在剛開始時,p 為父節點,r 為子節點,在左旋操作后,r 節點代替 p 節點的位置,p 節點成為 r 節點的左孩子,而 r 節點的左孩子成為 p 節點的右孩子。
右旋
右旋指的是圍繞某個節點向右旋轉,也就是順時針旋轉某個節點,此時父節點會被自己的左子節點取代,如下圖所示:
在 TreeMap 源碼中右旋的實現源碼如下:
右旋代碼說明:在剛開始時,p 為父節點 l 為子節點,在右旋操作后,l 節點代替 p 節點,p 節點成為 l 節點的右孩子,l 節點的右孩子成為 p 節點的左孩子。、
變色
對於紅黑樹來說,如果當前節點的左、右子節點均為紅色時,因為需要滿足紅黑樹定義的第四條特征(每個紅色節點必須有兩個黑色的子節點),所以需要執行變色操作,如下圖所示
常見面試題
(1) 紅黑樹和二叉樹有什么區別?
(2) 為什么工程中喜歡使用紅黑樹而不是其他二叉查找樹(優勢?)?
(3) 紅黑樹是如何保證自平衡的?