【21】 二叉查找樹——紅黑樹

1. 二叉查找樹(Binary Search Tree)

  1. 概念
    二叉查找樹是二叉樹中最常用的一種類型,也叫二叉搜索樹。顧名思義,二叉查找樹是爲了實現快速查找而生的。不過,它不僅僅支持快速查找一個數據,還支持快速插入、刪除一個數據。
    它是怎麼做到這些的呢? 這些都依賴於二叉查找樹的特殊結構。
    二叉查找樹要求,在樹中的任意一個節點,其左子樹中的每個節點的值,都要小於這個節點的值,而右子樹節點的值都大於這個節點的值。
  2. 二叉查找樹的查找、刪除、插入
    二叉查找樹的查找、插入操作都比較簡單易懂,但是它的刪除操作比較複雜一點。
    除了插入、刪除、查找操作之外,二叉查找樹中還可以支持快速地查找最大節點和最小節點、前驅節點和後繼節點。
  3. 二叉查找樹的有序輸出——中序遍歷
    二叉查找樹除了支持上面幾個操作之外,還有一個重要的特性,就是中序遍歷二叉查找樹,可以輸出有序的數據序列,時間複雜度是 O(n),非常高效。
  4. 二叉查找樹的時間複雜度分析
    極度不平衡的二叉查找樹的插入、刪除、查找操作的時間複雜度爲O(n)。
    平衡二叉查找樹的高度接近 logn,所以插入、刪除、查找操作的時間複雜度也比較穩定,是 O(logn)。

2. 有了如此高效的散列表,爲什麼還需要二叉樹?

第一,散列表中的數據是無序存儲的,如果要輸出有序的數據,需要先進行排序。而對於二叉查找樹來說,我們只需要中序遍歷,就可以在 O(n) 的時間複雜度內,輸出有序的數據序列。
第二,散列表擴容耗時很多,而且當遇到散列衝突時,性能不穩定,儘管二叉查找樹的性能不穩定,但是在工程中,我們最常用的平衡二叉查找樹的性能非常穩定,時間複雜度穩定在 O(logn)。
第三,籠統地來說,儘管散列表的查找等操作的時間複雜度是常量級的,但因爲哈希衝突的存在,這個常量不一定比 logn 小,所以實際的查找速度可能不一定比 O(logn) 快。加上哈希函數的耗時,也不一定就比平衡二叉查找樹的效率高。
第四,散列表的構造比二叉查找樹要複雜,需要考慮的東西很多。比如散列函數的設計、衝突解決辦法、擴容、縮容等。平衡二叉查找樹只需要考慮平衡性這一個問題,而且這個問題的解決方案比較成熟、固定。 最後,爲了避免過多的散列衝突,散列表裝載因子不能太大,特別是基於開放尋址法解決衝突的散列表,不然會浪費一定的存儲空間。
綜合這幾點,平衡二叉查找樹在某些方面還是優於散列表的,所以,這兩者的存在並不衝突。我們在實際的開發過程中,需要結合具體的需求來選擇使用哪一個。

3. 平衡二叉查找樹

平衡二叉樹的嚴格定義是這樣的:二叉樹中任意一個節點的左右子樹的高度相差不能大於 1。
完全二叉樹、滿二叉樹其實都是平衡二叉樹,但是非完全二叉樹也有可能是平衡二叉樹。
平衡二叉查找樹中“平衡”的意思,其實就是讓整棵樹左右看起來比較“對稱”、比較“平衡”,不要出現左子樹很高、右子樹很矮的情況。這樣就能讓整棵樹的高度相對來說低一些,相應的插入、刪除、查找等操作的效率高一些。

4. 如何定義一棵“紅黑樹”?

紅黑樹的英文是“Red-Black Tree”,簡稱 R-B Tree。
顧名思義,紅黑樹中的節點,一類被標記爲黑色,一類被標記爲紅色。除此之外,一棵紅黑樹還需要滿足這樣幾個要求:
根節點是黑色的;
每個葉子節點都是黑色的空節點(NIL),也就是說,葉子節點不存儲數據;
任何相鄰的節點都不能同時爲紅色,也就是說,紅色節點是被黑色節點隔開的;
每個節點,從該節點到達其可達葉子節點的所有路徑,都包含相同數目的黑色節點;

5. 爲什麼說紅黑樹是“近似平衡”的?

平衡二叉查找樹的初衷,是爲了解決二叉查找樹因爲動態更新導致的性能退化問題。所以,“平衡”的意思可以等價爲性能不退化。“近似平衡”就等價爲性能不會退化的太嚴重。

6. 思考

  1. 爲什麼在工程中大家都喜歡用紅黑樹這種平衡二叉查找樹?
    答:Treap、Splay Tree,絕大部分情況下,它們操作的效率都很高,但是也無法避免極端情況下時間複雜度的退化。儘管這種情況出現的概率不大,但是對於單次操作時間非常敏感的場景來說,它們並不適用。
    AVL 樹是一種高度平衡的二叉樹,所以查找的效率非常高,但是,有利就有弊,AVL 樹爲了維持這種高度的平衡,就要付出更多的代價。每次插入、刪除都要做調整,就比較複雜、耗時。所以,對於有頻繁的插入、刪除操作的數據集合,使用 AVL 樹的代價就有點高了。
    紅黑樹只是做到了近似平衡,並不是嚴格的平衡,所以在維護平衡的成本上,要比 AVL 樹要低。 所以,紅黑樹的插入、刪除、查找各種操作性能都比較穩定。
    對於工程應用來說,要面對各種異常情況,爲了支撐這種工業級的應用,我們更傾向於這種性能穩定的平衡二叉查找樹。
  2. 動態數據結構支持動態地數據插入、刪除、查找操作,除了紅黑樹,我們前面還學習過哪些呢?能對比一下各自的優勢、劣勢,以及應用場景嗎?
    散列表:插入刪除查找都是O(1), 是最常用的,但其缺點是不能順序遍歷以及擴容縮容的性能損耗。適用於那些不需要順序遍歷,數據更新不那麼頻繁的。
    跳錶:插入刪除查找都是O(logn), 並且能順序遍歷。缺點是空間複雜度O(n)。適用於不那麼在意內存空間的,其順序遍歷和區間查找非常方便。
    紅黑樹:插入刪除查找都是O(logn), 中序遍歷即是順序遍歷,穩定。缺點是難以實現。
    紅黑樹還不是很理解,有待補充。。。

7. 參考資料

  1. 王爭老師在極客時間的專欄《數據結構與算法之美》
  2. 專欄下的所有評論

8. 聲明

本文章是學習王爭老師在極客時間專欄——《數據結構與算法之美》的學習總結,文章很多內容直接引用了專欄下的回覆,推薦大家購買王爭老師的專欄進行更加詳細的學習。本文僅供學習使用,勿作他用,如侵犯權益,請聯繫我,立即刪除。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章