演算法導論 二叉搜尋樹

2021-07-04 20:39:54 字數 4923 閱讀 1166

搜尋樹資料結構支援許多動態集合操作,包括search、minimum、maximum、predecessor、successor、insert和delete等。因此,我們使用一棵搜尋樹既可以作為乙個字典又可以作為乙個優先佇列。

二叉搜尋樹上的基本操作所花費的時間與這棵樹的高度成正比。對於乙個有n個結點的完全二叉樹來說,這些操作的最壞執行時間為o(lgn)。然而,如果這棵樹是一條n個結點組成的線性鏈,那麼同樣的操作就要花費o(n)的最壞執行時間。隨機構造一棵二叉搜尋樹的期望高度為o(lgn),因此這樣一棵樹上的動態集合的基本操作的平均執行時間是o(lgn)。

1. 什麼是二叉搜尋樹

顧名思義,一棵二叉搜尋樹是以一棵二叉樹來組織的。這樣一棵樹可以使用乙個鍊錶資料結構來表示,其中每個結點就是乙個物件。除了key和衛星資料之外,每個結點還包含屬性left、right和p,它們分別指向結點的左孩子、右孩子和雙親。如果某個孩子結點和父結點不存在,則相應屬性值為nil。根結點是樹中唯一父指標為nil的結點。

二叉搜尋樹中的關鍵字總是以滿足二叉搜尋樹性質的方式來儲存:

設x是二叉搜尋樹中的乙個結點。如果y是x的左子樹中的乙個結點,那麼y.key <= x.key。如果y是x的右子樹中的乙個結點,那麼y.key >= x.key。

二叉搜尋樹的性質允許我們通過乙個簡單的遞迴演算法來按序輸出二叉搜尋樹中的所有關鍵字,這種演算法稱為中序遍歷(inorder tree walk)演算法。這樣命名的原因是輸出的子樹根的關鍵字位於左子樹的關鍵字值和右子樹關鍵字值之間。呼叫下面的過程inorder-tree-walk(t.root),就可以輸出一棵二叉搜尋樹t中的所有元素:

inorder-tree-walk(x)

1. if x != nil

2. inorder-tree-walk(x.left)

3. print x.key

4. inorder-tree-walk(x.right)

定理:如果x是一棵有n個結點子樹的根,那麼呼叫inorder-tree-walk(x)需要o(n)時間。

2. 查詢二叉搜尋樹

查詢

我們使用下面的過程在一棵二叉搜尋樹中查詢乙個具有給定關鍵字的結點。輸入乙個指向樹根的指標和乙個關鍵字k,如果這個結點存在,tree-search返回乙個指向關鍵字為k的結點的指標;否則返回nil。

tree-search(x, k)

1. if x == nil or k = x.key

2. return x

3. if k < x.key

4. return tree-search(x.left, k)

5. else return tree-search(x.right, k)

我們可以採用while迴圈來展開遞迴,用一種迭代的方式重寫這個過程。對於大多數計算機,迭代版本的效率要高得多。

iterative-tree-search(x, k)

1. while x != nil and k != x.key

2. if k < x.key

3. x = x.left

4. else x = x.right

5. return x

最大關鍵字元素和最小關鍵字元素

tree-minimum(x)

1. while x.left != nil

2. x = x.left

3. return x

tree-maximum(x)

1. while x.right != nil

2. x = x.right

3. return x

後繼和前驅

給定一棵二叉搜尋樹中的乙個結點,有時候需要按中序遍歷的次序查詢它的後繼。如果所有的關鍵字互不相同,則乙個結點x的後繼是大於x.key的最小關鍵字結點。一棵二叉搜尋樹的結構允許我們通過沒有任何關鍵字的比較來確定乙個結點的後繼。如果後繼存在,下面的過程將返回一棵二叉搜尋樹中的結點x的後繼;如果x是這棵樹中的最大關鍵字,則返回nil。

tree-successor(x)

1. if x.right != nil

2. return tree-minimum(x.right)

3. y = x.p

4. while y != nil and x == y.right

5. x = y

6. y = y.p

7. return y

同理,下面的程式返回前驅:

tree-predecessor(x)

1. if x.left != nil

2. return tree-maximum(x.left)

3. y = x.p

4. while y != nil and x == y.left

5. x = y

6. y = y.p

7. return y

定理:在一棵高度為h的二叉搜尋樹上,動態集合上的操作search、minimum、maximum、successor和predecessor可以在o(h)時間內完成。

3. 插入和刪除

插入

要將乙個新值v插入到一棵二叉搜尋樹t中,需要呼叫過程tree-insert。該過程以結點z作為輸入,其中z.key=v,z.left=nil,z.right=nil。這個過程要修改t和z的某些屬性,來把z插入到樹中的相應位置上。

tree-insert(t, z)

1. y = nil

2. x = t.root

3. while x != nil

4. y = x

5. if z.key < x.key

6. x = x.left

7. else x = x.right

8. z.p = y

9. if y == nil

10. t.root = z // tree t was empty

11. else if z.key < y.key

12. y.left = z

13. else y.right = z

刪除

從一棵二叉搜尋樹t中刪除乙個結點z的整個策略分為三種基本情況(如下所述),但只有一種情況有點棘手。

如果z沒有孩子結點,那麼只是簡單地將它刪除,並修改它的父結點,用nil作為孩子來替換z。

如果z只有乙個孩子,那麼將這個孩子提公升到z的位置上,並修改z的父結點,用z的孩子來替換z。

如果z有兩個孩子,那麼找z的後繼y(一定在z的右子樹中),並讓y佔據樹中z的位置。z的原來右子樹部分成為y的新的右子樹,並且z的左子樹成為y的新的左子樹。這種情況稍顯麻煩,因為還與y是否為z的右孩子有關。

從一棵二叉搜尋樹t中刪除乙個結點z,這個過程取指向t和z的指標作為輸入引數,它與前面概括的三種情況略有不同:

如果z沒有左孩子,那麼直接用其右孩子來替換z,這個右孩子可以是nil,也可以不是。當z的右孩子是nil時,此時這種情況歸為z沒有孩子結點的情形。當z的右孩子非nil時,這種情況就是z僅有乙個孩子結點的情形,該孩子是其右孩子。

如果z僅有乙個孩子且為其左孩子,那麼用其左孩子來替換z。

否則,z既有乙個左孩子又有乙個右孩子。我們要查詢z的後繼y,這個後繼位於z的右子樹中並且沒有左孩子。現在需要將y移出原來的位置進行拼接,並替換樹中的z。

如果y是z的右孩子,那麼用y替換z,並僅留下y的右孩子。

為了在二叉搜尋樹內移動子樹,定義乙個子過程transplant,它是用另一棵樹替換一棵子樹並成為其雙親的孩子結點。當transplant用一棵以v為根的子樹來替換一棵以u為根的子樹時,結點u的雙親就變為結點v的雙親,並且最後v成為u的雙親的相應孩子。

transplant(t, u, v)

1. if u.p == nil

2. t.root = v

3. else if u == u.p.left

4. u.p.left = v

5. else u.p.right = v

6. if v != nil

7. v.p = u.p

利用現成的transplant過程,下面從二叉搜尋樹t中刪除結點z的刪除過程:

tree-delete(t, z)

1. if z.left = nil

2. transplant(t, z, z.right)

3. else if z.right == nil

4. transplant(t, z, z.left)

5. else y = tree-minimum(z.right)

7. if y.p != z

8. transplant(t, y, y.right)

9. y.right = z.right

9. y.right.p = y

10. transplant(t, z, y)

11. y.left = z.left

12. y.left.p = y

定理:在一棵高為h的二叉搜尋樹上,實現動態集合操作insert和delete的執行時間均為o(h)。

演算法導論二叉搜尋樹

兩天寫完的,沒有認認真真的測試,可能有些bug,自己測試的資料能過,但是我的初始化有些問題,不知道該怎麼表示 二叉搜尋樹 include include using namespace std struct node void inorder search node root1 node tree ...

《演算法導論》筆記 二叉搜尋樹

演算法 資料結構 二叉搜尋樹 binary search tree 是經過一定地組織形成的有特定結構特徵的二叉樹,支援各種動態集合 dynamic set 操作 如insert delete maximum minimum等等 這些操作的時間複雜度與樹的高度成正比。一棵有n個節點的完全二叉樹 com...

演算法導論(5) 二叉搜尋樹

二叉搜尋樹 設x是二叉搜尋樹的乙個結點,如果y是x左子樹的乙個結點,那麼y.key x.key,如果y是x有字數的乙個結點,那麼y.key x.key。二叉樹有三種遍歷的方法 先序遍歷 輸出根的關鍵字在其左右子樹的關鍵字之前。中序遍歷 輸出根的關鍵字在其左右子樹的關鍵字之間。後序遍歷 輸出根的關鍵字...