搜尋樹資料結構支援許多動態集合操作,包括search/minimum/maximum/predecessor/successor/insert/delete等。因此,我們是用一棵搜尋樹既可以作為乙個字典又可以作為乙個優先佇列。
二叉搜尋樹的基本操作所花費的時間與這棵樹的高度成正比(所以相同的資料,組織成二叉搜尋樹後,其高度越低,則用於搜尋時效率越高)。一棵隨機構造的二叉搜尋樹的期望高度為o(lgn),因此這樣一棵樹上的動態集合的基本操作的平均執行時間為o(lgn)。
實際上,我們並不能總是保證隨機的構造二叉搜尋樹,然而可以設計二叉搜尋樹的變體,來保證基本操作具有好的最壞搜尋情況。紅黑樹就是這樣的乙個變體,它的樹高為o(lgn),b樹也是乙個變體,它特別適用於二次(磁碟)儲存器上的資料庫維護。
一棵二叉搜尋樹是以一棵二叉樹來組織的,這樣一棵樹可以使用乙個鍊錶資料結構來表示,其中每個結點就是乙個物件。除了key和衛星資料以外,每個結點還包含屬性left/right/parent。
二叉搜尋樹中的關鍵字總是以滿足二叉搜尋樹性質的方式來儲存:
設x是二叉搜尋樹中的乙個結點。如果y是x左子樹中的乙個結點,那麼y.key<=x.key,如果y是x右子樹中的乙個結點,那麼y.key>=x.key。
二叉搜尋樹的性質允許我們通過乙個簡單的遞迴演算法來按序輸出二叉搜尋樹中的所有關鍵字,這種演算法稱為中序演算法(inorder tree walk)。這樣命名的原因是輸出的子樹根的關鍵字位於其左子樹的關鍵字值和右子樹的關鍵字值之間。(類似的,先序遍歷(preorder tree walk)中輸出的根的關鍵字在其左右子樹的關鍵字之前,二後序遍歷(postorder tree walk)輸出的根的關鍵字在其左右子樹的關鍵字值之後).
inorder-tree-walk(x)
if x!=null
inorder-tree-walk(x.left)
print x.key
inorder-tree-walk(x.right)
tree-search(x, k)
if x==null || k==x.key
return x
if k在查詢中,從樹根開始遞迴期間遇到的結點形成了一條向下的簡單路徑,所以tree-search的執行時間是o(h),其中h是這棵樹的高度。
我們可以使用while迴圈來展開遞迴,用一種迭代方式重寫這個過程,對於大多數計算機,迭代版本的效率要高很多。
iterative-tree-search(x, k)
while x!=null and k!=x.key
if k(看到這裡的迭代版本,知道函式式程式設計裡面要用遞迴的乙個原因大概和迭代的話肯定要有變數是var型別而不是val型別的,瞎說一點)。
tree-minimum(x)
while x.left!=null
x=x.left
return x
tree-mininum(x)
if x.left==null
return x
else
return tree-minimum(x.left)
尋找最大元素的**是對稱的:
tree-maximum(x)
while x.right!=null
x=x.right
return x
tree-maximum(x)
if x.right==null
return x
else
return maximum(x.right)
給定一棵二叉搜尋樹中的乙個結點,有時候需要按照中序遍歷的次序查詢它的後繼,如果所有的關鍵字互不相同,則乙個結點x的後繼是大於x.key的最小關鍵字的結點。乙個二叉搜尋樹的結構允許我們通過沒有任何關鍵字的比較來確定乙個結點的後繼。
tree-successor(x)
if x.right!=null
return tree-minimum(x.right)
y=x.p
while y!=null and x==y.right
x=yy=y.p
return y
上面偽**的意思是如果結點x的右子樹非空,則x的後繼恰是x的柚子樹中的最左結點。如果結點x的右子樹為空並有乙個後繼y,那麼y就是x的最底層祖先(指的是最靠上的祖先),並且y的左孩子也是x的乙個祖先。為了找到y,只需要從x開始沿樹向上直到遇到這樣乙個結點:這個結點是它的parent的左結點。
tree-predecessor(x)
if x.left!=null
return tree-maximum(x.left)
y=x.p
while y!=null and x=y.left
x=yy=y.p
return y
插入和刪除操作會引起由二叉搜尋樹表示的動態集合的變化,一定要修改資料結構來反映這個變化,但修改要保持二叉搜尋樹的性質的成立。
tree-insert(t, z)
y=null
x=t.root
while x!=null
y=xif z.key指標x記錄了一條向下的簡單路徑,並查詢輸入項z要進行替換的null(這裡隱含的意味也就是z一定是新增作為乙個葉結點的)。該過程保持遍歷指標(trailing pointer)y作為x的parent。while迴圈是的y和x這兩個指標沿樹向下移動,向左或向右取決於z.key和x.key的比較,直到x變為null。這個null佔據的位置就是輸入項z要放置的地方。
從一棵二叉搜尋樹t中刪除乙個結點z的整個策略分為三種基本情況,但只有一種比較棘手:
為了在二叉搜尋樹內移動子樹,定義乙個子過程transplant,它是用另一棵子樹替換一棵子樹並成為其雙親的孩子結點。
transplant(t, u, v)
if u.p==null
t.root=v
elseif u=u.p.left
u.p.left=v
else
u.p.right=v
if v!=null
v.p=u.p
利用執行緒的transplant過程,下面是從二叉搜尋樹t中刪除結點z的全過程。
tree-delete(t, z)
if z.left==null
transplant(t, z, z.right)
else if z.right==null
transplant(t, z, z.left)
else
y=tree-minimum(z.right)
transplant(t, y, y.right)
y.right=z.right
y.right.p=y
transplant(t, x, y)
y.left=z.left
y.left.p=y
第十二章 二叉搜尋樹
施工中基本操作包括inorder tree walk minimum successor insert delete等。主要是用c 實現,部分會在日後補上 region 二叉樹基本操作 非遞迴版的中序遍歷 頭結點 public static void inorder tree walk node i...
《演算法導論》學習筆記 第十二章 二叉查詢樹
查詢樹以一種資料結構,它支援多種動態集合操作,包括search,minimum,maximum,predecessor,successor,insert以及delete,它既可以用作字典,也可以用作優先佇列。二叉查詢樹的執行的基本操作的時間與樹的高度成正比。對於一棵含有n個結點的完全二叉樹,這些操作...
演算法導論第十二章筆記
這裡的二叉樹型別分別包含關鍵字key,left right parent 指標分別指向左孩子 右孩子 雙親。若對應節點不存在就用nullptr空指標代替。這裡的二叉搜尋樹,對於任何節點x,其左子數的關鍵字最大不超過x key,其右子樹的關鍵字不低於x key。二叉樹遍歷有中序,先序,後序三種遍歷方式...