# [資料結構] CH10. Multi-way Search Trees ## M-way search trees * 在Binary search Tree中,每個node都只會有一個data和兩個pointer。 * 而在M-way search tree的**中,每個node則是有`M-1`個data和`M`個pointer。 * `M`被稱作是這棵M-way search tree的*degree* * 如果M=2,這顆M-way search tree就等於Binary Search Tree。 ```graphviz digraph Multiway { label="3-way search tree" node[shape=record] node1 [label="<f0>●|<f1>18|<f2>●|<f3>45|<f4>●"]; node2 [label="<f0>●|<f1>9|<f2>●|<f3>11|<f4>●"]; node3 [label="<f0>●|<f1>27|<f2>●|<f3>36|<f4>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>29|<f2>●|<f3>30|<f4>●"]; node6 [label="<f0>●|<f1>72|<f2>●|<f3>81|<f4>●"]; node1:f0->node2 node1:f2->node3 node1:f4->node4 node3:f2->node5 node4:f4->node6 } ``` * 在每個node中的data,必須按照大小排序。 * 同Binary search Tree,對於每個data `D`,`D`的leftpointer所指向的node中所有data必須小於`D`;rightpointer則反之。 * M-way search tree並不嚴格規定每個node都必須擁有`M-1`筆data。 * 任何一個node的data數可以是`1`~`M-1`。 ## B Trees * B Tree是M-way search tree的一種,但它對於node中的data限制更多。 * 和M-way search tree一樣,一棵degree=`M`的B Tree,每個node最多可擁有`M-1`筆data和`M`個pointer。 * 有些地方定義為 order 而非 degree,請注意自身學習時教學書的用詞。 * 感謝 **skysoul1024** 告知。 * 然而,除了root和leaf之外的所有node,必須至少擁有$\left \lceil \frac{M}{2} \right \rceil$個小孩(pointer)。 * Degree=4,至少有兩個小孩,一筆data。 * Degree=5,至少有三個小孩,兩筆data。 * root至少有兩個小孩。 * 所有葉子必須要在同一個level(同一高度)。 ```graphviz digraph BTree { label="B Tree, Degree=4" node[shape=record] node1 [label="<f0>●|<f1>45|<f2>●"]; node2 [label="<f0>●|<f1>29|<f2>●|<f3>32|<f4>●"]; node3 [label="<f0>●|<f1>49|<f2>●|<f3>63|<f4>●"]; node4 [label="<f0>●|<f1>18|<f2>●|<f3>27|<f4>●"]; node5 [label="<f0>●|<f1>30|<f2>●|<f3>31|<f4>●"]; node6 [label="<f0>●|<f1>36|<f2>●|<f3>39|<f4>●"]; node7 [label="<f0>●|<f1>46|<f2>●|<f3>47|<f4>●"]; node8 [label="<f0>●|<f1>54|<f2>●|<f3>59|<f4>●|<f5>61|<f6>●"]; node9 [label="<f0>●|<f1>67|<f2>●|<f3>72|<f4>●"]; node1:f0->node2 node1:f2->node3 node2:f0->node4 node2:f2->node5 node2:f4->node6 node3:f0->node7 node3:f2->node8 node3:f4->node9 } ``` ### 搜尋 ``` 在B Tree中搜尋n 1.從root開始,檢查數字n是否在該node中。 2.如果在該node找不到,找出n介於哪兩個數a,b之間,改為拜訪a,b之間的pointer指向的node。 3.若拜訪到的node為NULL,表示找不到該數字。 ``` * 在剛剛的範例中搜尋`59`: ```graphviz digraph BTree { label="B Tree, Degree=4" node[shape=record] node1 [label="<f0>●|<f1>45|<f2>●"]; node2 [label="<f0>●|<f1>29|<f2>●|<f3>32|<f4>●"]; node3 [label="<f0>●|<f1>49|<f2>●|<f3>63|<f4>●"]; node4 [label="<f0>●|<f1>18|<f2>●|<f3>27|<f4>●"]; node5 [label="<f0>●|<f1>30|<f2>●|<f3>31|<f4>●"]; node6 [label="<f0>●|<f1>36|<f2>●|<f3>39|<f4>●"]; node7 [label="<f0>●|<f1>46|<f2>●|<f3>47|<f4>●"]; node8 [label="<f0>●|<f1>54|<f2>●|<f3>59|<f4>●|<f5>61|<f6>●"]; node9 [label="<f0>●|<f1>67|<f2>●|<f3>72|<f4>●"]; node1:f0->node2 node1:f2->node3 node2:f0->node4 node2:f2->node5 node2:f4->node6 node3:f0->node7 node3:f2->node8 node3:f4->node9 } ``` 1.`59`比`45`大,拜訪右子樹 2.`59`介於`49`和`63`之間,拜訪中間那個node。 3.找到`59`ㄌ。 ## 插入 * 在B Tree加入新的data時,一定是先放在leaf的地方,如果容量爆了再做處理。 * 一般的Binary Search Tree是向下長,而B Tree是向上長的。 ``` 1.尋找data應該被放在哪個葉子。 2.如果葉子還沒滿,放入後結束。 3.如果葉子滿了: a)先把它大力地硬插進去這個node。 b)找到中間值,拆成左邊的node和右邊的node,並把中間值上提拿給老爸。 c)上提後的中間值,左pointer值向剛剛左邊的node,右邊同理。 d)因為老爸多了一個data,檢查老爸有沒有滿(遞迴步驟2or3)。 ``` --- * 範例1:在下面這棵B Tree中加入`4`。 * degree=5 ```graphviz digraph BTree { node[shape=record] node1 [label="<f0>●|<f1>18|<f2>●|<f3>45|<f4>●|<f5>72|<f6>●"]; node2 [label="<f0>●|<f1>7|<f2>●|<f3>8|<f4>●|<f5>9|<f6>●|<f7>11|<f8>●"]; node3 [label="<f0>●|<f1>21|<f2>●|<f3>27|<f4>●|<f5>36|<f6>●|<f7>42|<f8>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>81|<f2>●|<f3>89|<f4>●|<f5>90|<f6>●"]; node1:f0->node2 node1:f2->node3 node1:f4->node4 node1:f6->node5 } ``` * 先硬把`4`加進去。 ```graphviz digraph BTree { node[shape=record] node1 [label="<f0>●|<f1>18|<f2>●|<f3>45|<f4>●|<f5>72|<f6>●"]; node2 [label="<f-1>4|<f0>●|<f1>7|<f2>●|<f3>8|<f4>●|<f5>9|<f6>●|<f7>11|<f8>●"]; node3 [label="<f0>●|<f1>21|<f2>●|<f3>27|<f4>●|<f5>36|<f6>●|<f7>42|<f8>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>81|<f2>●|<f3>89|<f4>●|<f5>90|<f6>●"]; node1:f0->node2 node1:f2->node3 node1:f4->node4 node1:f6->node5 } ``` * 容量爆了,將中間值`8`往上提,並拆成左右並將指標指向正確位置。 ```graphviz digraph BTree { node[shape=record] node1 [label="<n2>●|<n1>8|<f0>●|<f1>18|<f2>●|<f3>45|<f4>●|<f5>72|<f6>●"]; node2a [label="<n2>●|<n1>4|<f0>●|<f1>7|<f2>●"]; node2b [label="<f4>●|<f5>9|<f6>●|<f7>11|<f8>●"]; node3 [label="<f0>●|<f1>21|<f2>●|<f3>27|<f4>●|<f5>36|<f6>●|<f7>42|<f8>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>81|<f2>●|<f3>89|<f4>●|<f5>90|<f6>●"]; node1:n2->node2a node1:f0->node2b node1:f2->node3 node1:f4->node4 node1:f6->node5 } ``` * 完成。 --- * 範例2:再加入`20`。 * 一樣先硬塞入`20`。 ```graphviz digraph BTree { node[shape=record] node1 [label="<n2>●|<n1>8|<f0>●|<f1>18|<f2>●|<f3>45|<f4>●|<f5>72|<f6>●"]; node2a [label="<n2>●|<n1>4|<f0>●|<f1>7|<f2>●"]; node2b [label="<f4>●|<f5>9|<f6>●|<f7>11|<f8>●"]; node3 [label="<n2>●|<n1>20|<f0>●|<f1>21|<f2>●|<f3>27|<f4>●|<f5>36|<f6>●|<f7>42|<f8>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>81|<f2>●|<f3>89|<f4>●|<f5>90|<f6>●"]; node1:n2->node2a node1:f0->node2b node1:f2->node3 node1:f4->node4 node1:f6->node5 } ``` * 中間值`27`往上提,拆左右。 ```graphviz digraph BTree { node[shape=record] node1 [label="<n2>●|<n1>8|<f0>●|<f1>18|<f2>●|<f3>27|<f4>●|<f5>45|<f6>●|<f7>72|<f8>●"]; node2a [label="<n2>●|<n1>4|<f0>●|<f1>7|<f2>●"]; node2b [label="<f4>●|<f5>9|<f6>●|<f7>11|<f8>●"]; node3a [label="<n2>●|<n1>20|<f0>●|<f1>21|<f2>●"]; node3b [label="<f4>●|<f5>36|<f6>●|<f7>42|<f8>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>81|<f2>●|<f3>89|<f4>●|<f5>90|<f6>●"]; node1:n2->node2a node1:f0->node2b node1:f2->node3a node1:f4->node3b node1:f6->node4 node1:f8->node5 } ``` * 上提後變成爸爸爆炸,只好換爸爸上提拆左右。 ```graphviz digraph BTree { node[shape=record] node0[label="<f0>●|<f1>27|<f2>●"]; node1a [label="<n2>●|<n1>8|<f0>●|<f1>18|<f2>●"]; node1b [label="<f4>●|<f5>45|<f6>●|<f7>72|<f8>●"]; node2a [label="<n2>●|<n1>4|<f0>●|<f1>7|<f2>●"]; node2b [label="<f4>●|<f5>9|<f6>●|<f7>11|<f8>●"]; node3a [label="<n2>●|<n1>20|<f0>●|<f1>21|<f2>●"]; node3b [label="<f4>●|<f5>36|<f6>●|<f7>42|<f8>●"]; node4 [label="<f0>●|<f1>54|<f2>●|<f3>63|<f4>●"]; node5 [label="<f0>●|<f1>81|<f2>●|<f3>89|<f4>●|<f5>90|<f6>●"]; node0:f0->node1a node0:f2->node1b node1a:n2->node2a node1a:f0->node2b node1a:f2->node3a node1b:f4->node3b node1b:f6->node4 node1b:f8->node5 } ``` * 完成。 ## 刪除 * 刪除在B Tree裡面就有點麻煩了。 * 我們分成兩種情形來討論: * 刪除的值不是在葉子(internal node)。 * 刪除的值在葉子(leaf node)。 ### Internal Node * 當刪除的值不在葉子上時,我們先直接將值刪除,然後找**左子樹最大值**代替原來的位置。 * 因為左子樹最大值被拿走了,因此情況就變成了下方的**刪除葉節點**了。 ### Leaf node * 葉節點要考慮的情形就有點多了: ``` 1.判斷data數是否低於下限,如果沒有,結束。 2.如果左右兄弟的data數量夠,向和左右的兄弟節點借值來補: a1)左邊的情形:先找到父親哪個pointer指向自己,將該pointer左邊的data放下來,並將左節點最大值向上推給父親取代。 a2)右邊的情形:先找到父親哪個pointer指向自己,將該pointer右邊的data放下來,並將右節點最小值向上推給父親取代。 3.如果兄弟都沒辦法借,只好向父親求救,一樣方為左右兩左情形: a1)左邊的情形:先找到父親哪個pointer指向自己,將該pointer左邊的data放下來,然後將自己和左兄弟兩個node合併。 a2)右邊的情形:先找到父親哪個pointer指向自己,將該pointer右邊的data放下來,然後將自己和右兄弟兩個node合併。 b)因為老爸被拿走一個data,回到步驟1但改為確認老爸的節點情況並做處理。 ``` * 簡單版: ``` 1.刪完沒事就沒事。 2.有事向兄弟求救。 3.兄弟救不了找老爸救。 4.老爸刪完沒事就沒事。 5.老爸有事向老爸的兄弟求救。 6.老爸的兄弟救不了找老爸的老爸。 7.LOOP ``` * 因為該部分步驟過多,用圖片很亂也很累,請參閱下方**其他資源**的部分。 ## 其他資源 * [B Tree模擬網頁](https://www.cs.usfca.edu/~galles/visualization/BTree.html) * 如果不想要手刻一次B Tree,一定要玩玩這個網頁!對插入和刪除的理解都很有幫助。 * 內含動畫,如太快可調整下方**Animation Speed**更改速度。 * [台科大 陳冠宇老師 上課講義](http://faculty.csie.ntust.edu.tw/~kychen/courses/2018_Fall_DS/2018-10-24%20Multi-way%20Search%20Trees.pdf) * 內含大量例子+圖片,可幫助思考。 ###### tags: `DS` `note`
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.