二叉排序樹、平衡二叉樹、B樹&B+樹、紅黑樹的設計動機、缺陷與應用場景


之前面試時曾被問到“如果實現操作系統的線程調度應該采用什么數據結構?”,因為我看過ucore的源碼,知道ucore是采用斜堆的方式實現的,可以做到O(n)的插入、O(1)的查找。我回答了斜堆,但面試官堅持讓我在B樹和紅黑樹之間選擇一個,由於實際上很少用到B樹和紅黑樹,所以我也不太清楚,只是隱約記得紅黑樹用於磁盤讀取比較好,好像和數據大小和數據連續性相關,顯然我記錯了。當時覺得紅黑樹還有一些應用,應該命中的可能性比較大,就隨意答了紅黑樹。當然回答錯啦,面試官還給我簡單講解了一下,一直想着有機會好好總結一下這幾個樹的設計動機、缺陷和應用場景。最近有些時間,決定好好復習一下,畢竟數據結構才是基礎。

為什么要引入樹呢?一般在學習數據結構時,往往先學習向量和列表,然后是棧與隊列。事實上,棧與隊列只是在組織數據時額外加入了一些限制,分別是先進后出和先進先出,向量和列表都可以實現這種策略。那么向量和列表又存在什么缺陷呢?一般來講,我們需要對數據結構做靜態操作和動態操作,靜態操作就是查找,動態操作就是插入和刪除。在C/C++中一般采用數組實現向量,采用鏈表實現列表。接下來我們看一下它們的靜態和動態操作的時間開銷。

向量 列表
靜態操作(查找) O(1) O(n)
動態操作(插入、刪除) O(n) O(1)

可以看到,已有的數據結構不能很好的平衡靜態操作和動態操作的時間開銷。

二叉排序樹、平衡二叉樹

一種簡單的方法是采用二叉排序樹(也叫二叉搜索樹,BST,Binary Search Tree),構造一顆二叉排序樹十分簡單。一般來講,大於根節點的放在根節點的右子樹上,小於根節點的放在根節點的左子樹上(如果等於根節點,則可視情況而定),如果寫程序的話,可以采用遞歸的方式,而且由於不存在重疊子問題的情況,因此遞歸的性能已經足夠好(不考慮棧溢出的情況)。
二叉排序樹在通常情況下可以達到O(lgN)的靜態、動態操作的時間復雜度,但是存在一種特殊情況,即輸入的數據本身就是有序的,這時二叉排序樹退化成向量。
為了消除二叉排序樹對於輸入敏感的特性,引入平衡二叉樹,事實上平衡二叉樹應該叫平衡二叉排序樹也許更合理。它采用遞歸的方式定義,這里我就不去查書上的標准定義了,只要保證每個節點左子樹和右子樹的高度差小於等於1就可以了。
平衡二叉樹(也叫AVL樹)就比較好用了,可以彌補二叉排序樹對輸入敏感的缺陷,可以確保靜態和動態操作的時間復雜度為O(loN)。

B樹&B+樹

1981年,Bill Gates曾說過這樣一段話“640KB is ought to be enough for anybody.”,可能當時intel生產的內存只有640KB,今天看來這句話也許很荒唐,目前好一點的機器都已經達到16GB的內存了,但是事實上這句話仍然有一定的道理。
只要學習過操作系統的人都知道,存儲器的訪問速度和容量往往成反比(這句話不是很妥當,只要領會意思就好),最快的當然是CPU上的寄存器,然后是cache(多級cache,不同硬件平台不同),然后是內存、外部硬盤等等。當兩個處在不同層級上的存儲器彼此之間交互數據時(例如內存與硬盤之間),我們稱之為I/O,事實上這種I/O操作相當耗時,應該盡可能避免。
B樹的出現就是為了解決這個問題,B樹由於是多路二叉樹,事實上它的高度要遠低於二叉平衡樹。一般來講,我們可以認為二叉平衡樹每下降一層需要執行一次磁盤I/O操作,以1G數據為例,平均需要30次磁盤I/O才能讀取到數據,而B樹每下降一層,每個超級結點都會讀入多個關鍵碼,需要的磁盤I/O次數小於AVL樹,因此B樹適用於實現磁盤的讀寫邏輯。

紅黑樹

對於向量、列表、樹和圖來說,它們每次的動態操作都會完全遺忘之前的狀態,轉而到達全新的狀態,這種數據結構稱為ephemeral structure。另一種數據結構可以記錄某一歷史時刻的狀態,在訪問時可以根據版本好+目標數據進行訪問,這種數據結構稱為persistent structure。事實上,紅黑樹可以實現這種對歷史版本的記錄,我也不懂它為什么有這么奇妙的功能,這里就不再深入研究了,因為我覺得研究明白以后我還是會忘,有機會再看。

結論

回到最初的問題,即面試官提到的問題。我覺得面試官強迫我在B樹和紅黑樹之間選擇沒有多少道理,因此線程調度的數據量很小,不涉及磁盤I/O的問題,同時線程調度好像也沒有記錄歷史版本的需求,而這兩個數據結構的靜態和動態操作的時間復雜度一樣,空間復雜度也接近,因此它們兩個應該差不多才對。話說,它們兩個的實現效率都不如斜堆。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM