1. 程式人生 > >紅黑樹與AVL樹

紅黑樹與AVL樹

target 相同 spa search htm 解決 evel 所有應用 二叉搜索樹

概述:本文從排序二叉樹作為引子,講解了紅黑樹,最後把紅黑樹和AVL樹做了一個比較全面的對比。

1 排序二叉樹

排序二叉樹是一種特殊結構的二叉樹,可以非常方便地對樹中所有節點進行排序檢索。 排序二叉樹要麽是一棵空二叉樹,要麽是具有下列性質的二叉樹: ? 若它的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值; ? 若它的右子樹不空,則右子樹上所有節點的值均大於它的根節點的值; ? 它的左、右子樹也分別為排序二叉樹。 下圖顯示了一棵排序二叉樹:

對排序二叉樹,若按中序遍歷就可以得到由小到大的有序序列。中序遍歷得: {2,3,4,8,9,9,10,13,15,18} 排序二叉樹雖然可以快速檢索,但在最壞的情況下

:如果插入的節點集本身就是有序的,要麽是由小到大排列,要麽是由大到小排列,那麽最後得到的排序二叉樹將變成鏈表:所有節點只有左節點(如果插入節點集本身是大到小排列);或所有節點只有右節點(如果插入節點集本身是小到大排列)。在這種情況下,排序二叉樹就變成了普通鏈表,其檢索效率就會很差

2 紅黑樹

《算法導論》關於紅黑樹的定義:

正如在CLRS中定義的那樣(CLRS指的是就是算法導論這本書《Introduction to Algorithms》,CLRS是該書作者Cormen, Leiserson, Rivest and Stein的首字母縮寫),一棵紅黑樹是指一棵滿足下述性質的二叉搜索樹(BST, binary search tree):

1. 每個結點或者為黑色或者為紅色。

2. 根結點為黑色。

3. 每個葉結點(實際上就是NULL指針)都是黑色的。

4. 如果一個結點是紅色的,那麽它的兩個子節點都是黑色的(也就是說,不能有兩個相鄰的紅色結點)。

5. 對於每個結點,從該結點到其所有子孫葉結點的路徑中所包含的黑色結點數量必須相同。

數據項只能存儲在內部結點中(internal node)。我們所指的"葉結點"在其父結點中可能僅僅用一個NULL指針表示,但是將它也看作一個實際的結點有助於描述紅黑樹的插入與刪除算法,葉結點一律為黑色。 定義詳解: 根據性質 5:紅黑樹從根節點到每個葉子節點的路徑都包含相同數量的黑色節點,因此從根節點到葉子節點的路徑中包含的黑色節點數被稱為樹的“黑色高度(black-height)

”。 性質 4 則保證了從根節點到葉子節點的最長路徑的長度不會超過任何其他路徑的兩倍。假如有一棵黑色高度為 3 的紅黑樹:從根節點到葉節點的最短路徑長度是 2,該路徑上全是黑色節點(黑節點 – 黑節點 – 黑節點)。最長路徑也只可能為 4,在每個黑色節點之間插入一個紅色節點(黑節點 – 紅節點 – 黑節點 – 紅節點 – 黑節點),性質 4 保證絕不可能插入更多的紅色節點。由此可見,紅黑樹中最長路徑就是一條紅黑交替的路徑。 根據定義我們做如下練習: -不符合定義的一顆非紅黑樹: 紅黑樹的這5個性質中,第3點是比較難理解的,但它卻非常有必要。我們看圖1中的左邊這張圖,如果不使用黑哨兵,它完全滿足紅黑樹性質,結點50到兩個葉結點8和葉結點82路徑上的黑色結點數都為2個。但如果加入黑哨兵後(如圖1右圖中的小黑圓點),葉結點的個數變為8個黑哨兵,根結點50到這8個葉結點路徑上的黑高度就不一樣了,所以它並不是一棵紅黑樹。 -兩顆正確的紅黑樹: 定理

一棵擁有n個內部結點的紅黑樹的樹高h<=2log(n+1)

由此我們可以得出結論:對於給定的黑色高度為 N 的紅黑樹,從根到葉子節點的最短路徑長度為 N-1,最長路徑長度為 2 * (N-1)。 提示:排序二叉樹的深度直接影響了檢索的性能,正如前面指出,當插入節點本身就是由小到大排列時,排序二叉樹將變成一個鏈表,這種排序二叉樹的檢索性能最低:N 個節點的二叉樹深度就是 N-1。 紅黑樹通過上面這種限制來保證它大致是平衡的——因為紅黑樹的高度不會無限增高,這樣保證紅黑樹在最壞情況下都是高效的,不會出現普通排序二叉樹的情況。 由於紅黑樹只是一個特殊的排序二叉樹,因此對紅黑樹上的只讀操作與普通排序二叉樹上的只讀操作完全相同,只是紅黑樹保持了大致平衡,因此檢索性能比排序二叉樹要好很多。 但在紅黑樹上進行插入操作和刪除操作會導致樹不再符合紅黑樹的特征,因此插入操作和刪除操作都需要進行一定的維護,以保證插入節點、刪除節點後的樹依然是紅黑樹。

3 紅黑樹和AVL樹的比較

1. 紅黑樹並不追求“完全平衡”——它只要求部分地達到平衡要求,降低了對旋轉的要求,從而提高了性能。 紅黑樹能夠以O(log2 n) 的時間復雜度進行搜索、插入、刪除操作。此外,由於它的設計,任何不平衡都會在三次旋轉之內解決。當然,還有一些更好的,但實現起來更復雜的數據結構,能夠做到一步旋轉之內達到平衡,但紅黑樹能夠給我們一個比較“便宜”的解決方案。紅黑樹的算法時間復雜度和AVL相同,但統計性能比AVL樹更高。 當然,紅黑樹並不適應所有應用樹的領域。如果數據基本上是靜態的,那麽讓他們待在他們能夠插入,並且不影響平衡的地方會具有更好的性能。如果數據完全是靜態的,做一個哈希表,性能可能會更好一些。 紅黑樹是一個更高效的檢索二叉樹,因此常常用來實現關聯數組。典型地,JDK 提供的集合類 TreeMap 本身就是一個紅黑樹的實現。 IBM DevelopWorks 上一篇文章講解非常好,供參考。 TreeMap 和 TreeSet 是 Java Collection Framework 的兩個重要成員,其中 TreeMap 是 Map 接口的常用實現類,而 TreeSet 是 Set 接口的常用實現類。雖然 HashMap 和 HashSet 實現的接口規範不同,但 TreeSet 底層是通過 TreeMap 來實現的,因此二者的實現方式完全一樣。而 TreeMap 的實現就是紅黑樹算法。 對於 TreeMap 而言,由於它底層采用一棵“紅黑樹”來保存集合中的 Entry,這意味這 TreeMap 添加元素、取出元素的性能都比 HashMap 低:當 TreeMap 添加元素時,需要通過循環找到新增 Entry 的插入位置,因此比較耗性能;當從 TreeMap 中取出元素時,需要通過循環才能找到合適的 Entry,也比較耗性能。 但 TreeMap、TreeSet 比 HashMap、HashSet 的優勢在於:TreeMap 中的所有 Entry 總是按 key 根據指定排序規則保持有序狀態,TreeSet 中所有元素總是根據指定排序規則保持有序狀態。 2 AVL樹是最先發明的自平衡二叉查找樹。在AVL樹中任何節點的兩個兒子子樹的高度最大差別為一,所以它也被稱為高度平衡樹。查找、插入和刪除在平均和最壞情況下都是O(log n)。增加和刪除可能需要通過一次或多次樹旋轉來重新平衡這個樹。 引入二叉樹的目的是為了提高二叉樹的搜索的效率,減少樹的平均搜索長度.為此,就必須每向二叉樹插入一個結點時調整樹的結構,使得二叉樹搜索保持平衡,從而可能降低樹的高度,減少的平均樹的搜索長度. AVL樹的定義:
一棵AVL樹滿足以下的條件: 1>它的左子樹和右子樹都是AVL樹 2>左子樹和右子樹的高度差不能超過1
性質:
1>一棵n個結點的AVL樹的其高度保持在0(log2(n)),不會超過3/2log2(n+1) 2>一棵n個結點的AVL樹的平均搜索長度保持在0(log2(n)). 3>一棵n個結點的AVL樹刪除一個結點做平衡化旋轉所需要的時間為0(log2(n)).
為了保證平衡,AVL樹中的每個結點都有一個平衡因子(balance factor,以下用BF表示),它表示這個結點的左、右子樹的高度差,也就是左子樹的高度減去右子樹的高度的結果值。AVL樹上所有結點的BF值只能是-1、0、1。反之,只要二叉樹上一個結點的BF的絕對值大於1,則該二叉樹就不是平衡二叉樹。下圖演示了平衡二叉樹和非平衡二叉樹。 從1這點來看紅黑樹是犧牲了嚴格的高度平衡的優越條件為代價紅黑樹能夠以O(log2 n)的時間復雜度進行搜索、插入、刪除操作。此外,由於它的設計,任何不平衡都會在三次旋轉之內解決。當然,還有一些更好的,但實現起來更復雜的數據結構能夠做到一步旋轉之內達到平衡,但紅黑樹能夠給我們一個比較“便宜”的解決方案。紅黑樹的算法時間復雜度和AVL相同,但統計性能比AVL樹更高.

紅黑樹與AVL樹