1. 什么是二叉搜索樹
顧名思義,二叉搜索樹是以一棵二叉樹來組織的。如下圖,這樣的一棵樹可以使用一個鏈表數據結構來表示,其中的每一個節點是一個對象。除了key和衛星數據之外,每個節點還包含屬性left(左孩子)、right(右孩子)、和p(雙親)(若不存在,則值為NIL)。
二叉搜索樹中的關鍵字總是以滿足二叉搜索樹性質的方式存儲:
設x是二叉搜索樹的一個節點。如果y是x左子樹中的一個節點,那么y.key≤x.key。如果y是x右子樹中的一個節點,那么y.key≥x.key。
二叉搜索樹性質允許我們使用一種簡單的遞歸算法來按一定的順序輸出二叉搜索樹中的所有關鍵字。我們常用的有先序遍歷(輸出的子樹根的關鍵字位置位於左子樹關鍵字和右子樹關鍵字之間)、中序遍歷、后序遍歷。
下面給出先序遍歷的遞歸算法:
我們可以證明:遍歷一棵有n個節點的二叉搜索樹需要花費θ(n)的時間(證明略)。
2. 查詢二叉搜索樹
這一小節,我們來討論二叉搜索樹的諸如:SEARCH,MINIMUM,MAXIMUN,SUCCESSOR,PERDECESSOR操作。
我們使用如下一種算法去查詢一棵二叉搜索樹。該方法要求輸入一個指向根節點的指針x和待查找的關鍵字k;輸出為指向關鍵字為k的節點的指針(若存在。否則輸出NIL)。
我們很容易知道,該查詢算法的時間為O(h),其中h為樹的高度。
更好地,我們可以用如下迭代來替代遞歸,因為遞歸可能會造成棧內存溢出,在大多數計算機上,迭代版本的效率要更高。
由於二叉搜索樹性質的存在,我們可以很容易的找出樹中的最大和最小關鍵字元素。
同樣,上面的兩種方法均可以在O(h)時間內完成。
給定一棵二叉搜索樹的某個節點,有時我們需要按中序遍歷的次序去查找該節點的前驅和后驅。如在下圖中,我們容易看出,key為4的節點的前驅是key為3的節點,后驅是key為6的節點;key為7的節點的前驅是key為6的節點,后驅是key為9的節點。
下面是求某節點后驅的算法:
解釋一下上面求后驅的過程。我們分兩種情況討論:
① 如果x的右子樹不為NIL,那么x的后繼即為右子樹中key最小的元素。
② 如果x的右子樹為NIL,那么x的后繼節點必將在其祖先節點(包括父節點)中產生。並且該祖先節點必須是從下至上,第一次滿足自己為自己父節點的右節點。
同理,我們可以求出x的前驅節點,這里就不給出算法了。
很容易看出,它們所需的時間均為O(h)。
由此,我們得出:在一棵高度為h的二叉搜索樹上,集合操作SEARCH,MINIMUM,MAXIMUN,SUCCESSOR,PERDECESSOR都可以在O(h)時間內完成。
3. 插入和刪除
相比刪除操作,插入操作相對簡單一些。下面給出insert算法。該算法的作用是,將一個新節點z插入到一棵二叉搜索樹T中。
算法很簡單,這里就不做說明了。
同樣可以看出,插入操作的時間為O(h)。
我們按照被刪除的節點的子節點個數,分以下三種情況來討論:
① 被刪除節點沒有孩子。只需要修改其父節點,用NIL去替換自己。
② 被刪除節點有一個孩子。也只需要修改其父節點,用這個孩子去替換自己。
③ 被刪除節點有兩個孩子。那么先找z的后繼y(一定在z的右子樹中),並讓y占據樹中z的位置。z的原來的右子樹部分稱為y的新的右子樹,並且z的左子樹成為y的左子樹。
前兩種情況比較簡單,至於第三種情況,我們還可以細分:
① 如果z的后繼y就是z的右孩子(即y沒有左孩子),直接用y代替z,並保留y的右子樹,如下圖所示:
② 如果z的后繼y不是z的右孩子,先用y的右孩子替換y,再用y替換z。如下圖所示:
為了實現上面的過程,我們先來實現transplant過程。該過程能夠實現讓子樹v代替子樹μ。實現算法如下:
利用transplant,我們根據上述的討論來實現刪除操作:
注意到上述刪除操作過程並沒有給出我們上述討論中,情況①中z沒有孩子的情況。事實上,上述討論中情況①已經被包含在情況②中,即z沒有孩子的情況等價於z有一個key為NIL的左孩子或有一個key為NIL的右孩子。
分析該算法,我們發現除了transplant外,其他操作均花費常量時間。因此刪除操作將花費O(h)時間。
綜合以上的所有分析,我們可知:二叉搜索樹上的每個基本操作都可以在O(h)時間內完成(其中h為樹的高度)。
4. 隨機構建二叉搜索樹
我們先給出隨機構建二叉搜索樹的定義:向一棵空樹隨機的插入n個關鍵字而得到的樹。這里隨機的意思是n個關鍵字的n!種排列都等可能的出現。
我們要證明如下定理:
一棵有n個不同關鍵字的隨機構建二叉搜索樹的期望高度為O(lgn)。
先定義三個隨機變量Xn,Yn,Rn,其中,Xn表示一棵有n個不同關鍵字的隨機構建二叉搜索樹的高度;Yn=2^Xn表示二叉搜索樹的指數高度(exponential height)。Rn表示當在n個不同的關鍵字中選擇一個作為樹根時,該關鍵字在這n個關鍵字集合中的秩(rank)(即Rn表示這些關鍵字排好序后這個關鍵字應占據的位置)。這樣如果Rn = i,那么表示根的左子樹有i-1個元素,右子樹有n-i個元素,此時有:
Yn = 2 · max(Yi-1, Yn-i)
我們再定義一個指示器隨機變量Zn,i,Zn,i = I{Rn = i}。因為Rn對於集合{1,2,…,n}中的任一元素都是等可能的,因此有:
p{Rn = i} = 1 / n,(i=1,2,…,n)
E(Zn,i) = 1 / n
由於Zn,i只等於1或0,Yn = 2 · max(Yi-1, Yn-i) =
於是有:
在上式最后的和式中,Y[0],Y[1],…,Y[n-1]都會出現兩次(E[Yi-1]和E[Yn-i]都會出現),因此:
上式是一個遞歸式,我們可以猜測 ,並用數學歸納法可證明(這里略)。
有Jensen不等式,我們可得進一步可得
兩邊去對數,最終得: