b樹的刪除自己弄了好長時間,才有一點點的眉目,特此記下來,以供以後複習:
一、總之兩條原則:
與插入情況相對稱,除了根節點外(根節點個數不能少於1),b樹的關鍵字數不能少於t-1個,對於簡單的刪除情況,我們定位到該關鍵字所在的某個結點中,如果這個節點中關鍵字個數恰好是t-1,如果直接刪除這個關鍵字,就會違反b樹的規則;這時我們可以考慮兩種兩種處理方案:
a、把這個結點與其相鄰結點合併:合併時需要把父節點的乙個關鍵字加進來;
適合的情況:其相鄰結點只有t-1個關鍵字,其父節點至少有t個關鍵字,否則就會違反b樹的規則;
b、從相鄰結點借乙個關鍵字過來,借的過程中,需要中轉父節點
適合情況:相鄰節點至少有t個關鍵字
二、為了避免類似插入要進行的回溯
解決方案:
弄乙個關鍵字方法:
1、如果相鄰結點有的話就從相鄰結點通過父節點中轉;
2、如果相鄰節點都沒有的話,說明相鄰結點都只有t-1個關鍵字,就直接與相鄰結點合併以滿足要求;
三、步驟:
1、首先沿根節點進行處理:訪問到根節點,如果根節點只有乙個關鍵字,且其左右子女只有t-1個關鍵字,則要把兩子女合併,根節點的關鍵字下移,合併後的節點作為b樹新的根節點。(這也是b樹高度下降的唯一方式);然後在繼續確定key所在的子樹,刪除關鍵字key;
2、如果訪問到的結點是葉子結點
(能保證此葉節點一定有t個關鍵字,刪除key後仍然保持b樹的性質),則在葉子結點中尋在key值並刪除之,否則無key值;
3、如果訪問到的結點是內結點x
1)找到關鍵字key在x中(能保證該結點一定有t個關鍵字)。假設關鍵字key在此節點的位置i處,c(i)[x]為其左鄰居left,c(i+1)[x]為其右鄰居right(兩者都存在)
2)如果某乙個鄰居結點的關鍵字個數》=t,則找到以該鄰居結點為根節點的子樹中最小或最大關鍵字k'(key的後繼或者前驅),然後遞迴的刪除k',最後在x中用k'代替key;(這裡面的前驅和後繼,視情況而定);
3)如果兩個鄰居節點的關鍵字個數都== t-1,則將這兩個鄰居合併為乙個新節點y,然後關鍵字key下移到合併後的節點y中,再遞迴刪除y中的key;
4、如果關鍵字不在x中,則key必在以c(i)[x]為根的某個子樹中(x結點至少有t個關鍵字),記current = c(i)[x]
1)如果current結點的的關鍵字個數》= t,下降至current,遞迴尋找key然後刪除之;
2)current結點的關鍵字個數 == t-1,找到該節點的鄰居結點left == c(i-1)[x](i==1時不存在), y == c(i+1)[x] (i== x->keynum +1 時不存在),這時就有兩種情況:
a、此節點的鄰居(left、right)中有乙個結點至少有有t個關鍵字,可從通過鄰居中轉借父節點乙個關鍵字;
b、此節點的鄰居(left、right)都只有t-1個關鍵字,只能將此節點和其中乙個結點合併,並下移父節點x的乙個關鍵字(因為x結點至少有t個關鍵字,少乙個關鍵字否也能保證b樹的性質),接著下移至current,遞迴尋找key然後刪除之;
四、給圖進行解答:
4.2 現在操作都轉移到btree_delete_nonone(x, key)函式中,進入這個函式的前提是x結點的關鍵字個數必》= t;對於此函式我們又要另外分幾種情況進行談論:
4.2.1、對情況a進行討論:
4.2.2、對情況b進行討論:
我在寫程式的時候,差點忽略了
以下重要的一點:
最後一種情況btree_mergenode(x, i-1, left, current)執行後,記住以current指向的結點已經被銷毀,這個時候做個操作 : current = left,然後在對current所指向的結點遞迴呼叫btree_delete_nonone(current, key);
5、總結
以上便是b樹刪除乙個結點的總過程,
在這個過程中我們
:首先討論了根節點的特殊情況,並且
它也是b樹高度下降的唯一途徑;
其實討論了btree_delete_nonone(x, key)函式,對其
兩種大情況
進行了討論,同時對第二種大情況又分了兩種case
進行了討論,並且這兩種case中又分了好多個case;在這些不同的case中我們用到了
:1)btree_
mergenode(x, i, y
, z)
函式:將x
結點的兩個相鄰的
子女y、z進行合併,同時
適當改變x結點;
2)btree_shift_rightchi
ld(x,
i, left, current)
函式:將x結點i
處的關鍵字移動到current
第乙個位置處,將
左鄰居最後乙個關鍵字
移動到x結點i處
(還要做其餘指標的處理
);3)btree
_shift_le
ftchil
d(x, i, current, right)
函式:通過x結點
給current結點
增加乙個關鍵字;
4)btree_successor(x
)函式:尋找b樹中最小的關鍵字(用在程式裡面就是尋找某個關鍵字的後繼
),x是b樹的
根節點;
5)btree_pre
cursor(x)函式:
尋找b樹中最大的關鍵字(用在程式裡面就是尋找某個關鍵字的前驅),x是b樹的根節點;
等過幾天我再寫一篇blog將這些操作的偽**附上,並貼上自己寫的程式,加油加油加油!!!!!!
最後,經過我的理解,b樹的刪除,不管是key關鍵字是在內結點還是在葉結點,都是在「葉節點」進行刪除:
1)key關鍵字在葉節點:略過
2)key關鍵字在內結點:
case1:找到其前驅或者後繼(這些前驅和後繼必在葉節點上),然後遞迴刪除這些前驅和後繼,最後在用前驅和後繼代替key所在的位置,這些操作其實可以看做在「葉節點上」刪除key;
我將在隨後幾天的時間裡寫成這些函式的偽**,同時將自己的程式附上;
case2:將其左右鄰居合併成乙個結點y,key關鍵字下降到結點y中,然後在呼叫btree_delete_nonone(y, key),返回到原來的問題:y是葉節點,就在葉節點中刪除key,y不是葉節點,又返回到2)這種情況;
3)key關鍵字在不在內結點,key關鍵字必在以該內結點的某個子女為根節點的子樹上:
case1:該子女結點關鍵字個數》=t,呼叫btree_delete_nonone(子女, key),遞迴尋找key並刪除,又回到原來的大問題;
case2:該子女結點關鍵字個數== t-1,從其關鍵字結點個數》=t的鄰居結點借乙個關鍵字過來,否則與其鄰居結點合併,在呼叫btree_delete_nonone(子女, key)
,遞迴尋找key並刪除,又回到原來的大問題;
《演算法導論》第18章 b樹
B樹的刪除操作
把b樹壓縮成陣列的結構,二維的樹是由 一維的陣列 進化 拉伸 而來的,所以我們先還原成 一維陣列 可以簡化對刪除操作的思考 如前趨值 後趨值的概念就是一維陣列中的 實質上,b樹的刪除和二叉樹的刪除很相似,都是用其左 右分支的最大值 最小值來覆蓋 刪除 當前要刪除的關鍵字,然後再遞迴刪除此左 右分支的...
B樹(又稱B 樹)插入 刪除操作
b樹是一種平衡的多分樹,通常我們說m階的b樹,它必須滿足如下條件 1 每個結點至多有m個子結點 2 除根結點和葉結點外,其它每個結點至少有ceil m 2 個子結點 3 根結點至少有兩個子結點 唯一例外的是根結點就是葉子結點 4 所有的葉結點在同一層 5 有k個子結點的非根結點恰好包含k 1個關鍵碼...
B 樹的插入 刪除操作
include include define maxm 10 b 樹最大階數 typedef int keytype keytype是關鍵字型別 typedef struct node btnode typedef struct b 樹的查詢結果型別 result int m m階b 樹作為全域性變...