刪除操作
刪除操作比較複雜,主要是因為刪除的項可能在葉子節點上也可能在非葉子節點上,而且刪除後可能導致不符合B樹的規定,這裡暫且稱之為導致B樹不平衡,於是要進行一些合併、左旋、右旋等操作,使之符合B樹的規定(即讓B樹平衡)。另外,如果是刪除非葉子節點項需要先找到中序前驅來替換。
情況一
要刪除的項在葉子節點上且不影響B樹的平衡結構,比如刪除“I”,從根節點開始查詢,“I”大於“D”,往第二個分支,
逐一與節點內項的值進行比較,“I”大於“F”,繼續比較,“I”大於“H”繼續比較,“I”小於“K”,所以往第三個分支繼續往下查詢,
此時找到“I”,
直接刪除“I”,完成刪除操作。
情況二
要刪除的項在葉子節點上,刪除後打破平衡需要從右兄弟節點中借項,而且右兄弟節點有足夠的項借給它。比如刪除“G”,從根節點開始查詢,“G”大於“D”,往右子樹,
逐一比較節點內項的值,發現應該往第二個分支,
找到“G”,
此時發現“G”節點的右兄弟節點有項可以借給它,於是刪除“G”,然後進行左旋操作,左旋即原來的父節點“H”下移到左子節點填補原來的“G”節點,右子節點中最小值的項“I”提升到父節點,最終如下,
完成刪除操作。
情況三
要刪除的項在葉子節點上,刪除後打破平衡需要從左兄弟節點中借項,而且左兄弟節點有足夠的項借給它。比如刪除“L”,從根節點開始查詢,“L”大於“D”,往右子樹,
逐一比較節點內項的值,發現應該往第四個分支,
找到“L”,
此時發現“L”節點的左兄弟節點有項可以借給它,於是刪除“L”,然後進行右旋,右旋即原來的父節點“K”下移到右子節點填補原來的“L”節點,左子節點中最大值的項“J”提升到父節點,最終如下,
完成刪除操作。
情況四
要刪除的項在葉子節點上,刪除後打破平衡,而且左右兄弟節點都沒有項可以借給它。比如刪除“G”,從根節點開始查詢,“G”大於“D”,往右子樹,
逐一比較節點內項的值,發現應該往第二個分支,
找到“G”,
此時發現“G”節點刪除掉後,左右兄弟節點都無法借項給它,執行合併操作,
合併操作主要是將父節點對應的項“F”下移到左子節點中,同時也將右子節點中剩餘的項全部也移到左子節點中(注意這裡右子節點刪除“G”項後已無其他項),最終結果如下,完成刪除操作。
需要注意的是如果執行合併操作後使父節點不平衡,則需要繼續對父節點繼續進行平衡處理。比如下面的例子,需要刪除“C”項,從根節點開始於“D”比較,小於“D”則往往第一個分支,
逐一與子節點內的項比較,“C”大於“B”則往第二個分支,
找到“C”,
此時發現“C”項刪除掉後,左右兄弟節點都無法借項給它,
執行合併操作,將父節點對應的項“B”下移到左子節點中,同時也將右子節點中剩餘的項全部也移到左子節點中,合併後結果如下,父節點已經變成空了,樹不平衡,
此時父節點的右兄弟節點可以借項給它,即執行左旋操作,父節點的父節點“D”下移到父節點,父節點的兄弟節點的最左邊項“F”上升,
另外,左旋操作還包括要將移動項“F”對應節點的第一個分支(即“E”)移到父節點“D”的最右分支,最終結果如下,
情況五
要刪除的項在非葉子節點上。比如刪除“M”,從根節點開始查詢,“M”大於“H”,往第二個分支,
逐一比較子節點內的項,找到“M”,
非葉子節點項的刪除的第一步就是要先找到對應的中序前驅,即第一個分支子節點中最大值的項,
然後一直往最後一個分支找,最終找到“L”為前驅,將其提升到待刪除項“M”的位置,導致了樹不平衡,但它發現兄弟節點可以借項給它,
於是進行右旋操作,父節點“K”下移到原來前驅的位置,左兄弟節點最右邊的項“J”提升到父節點,另外如果左兄弟節點“J”項有右子節點的話,也需要掛到“K”節點的左邊。最終完成刪除操作。
除此之外,再看看刪除根節點的情況,刪除只有一個項的根節點,比如刪除“D”,
先找中序前驅,即第一個分支子節點中最大值的項,
一直往最後一個分支找,最終找到“C”為前驅,將其提升到根節點中,
此時引起不平衡,而且原來“C”節點的左右兄弟節點都無法借項給它,
此時只能做合併處理,將父節點的項“B”下移到左子節點,合併後原來的父節點變為空,產生了不平衡,此時它的兄弟節點可以借項給它,所以需要執行左旋操作,
左旋即將“C”下移,“F”提升,
而且還要將“E”項掛到“C”節點上,最終如下。
-------------推薦閱讀------------
我的開源專案彙總(機器&深度學習、NLP、網路IO、AIML、mysql協議、chatbot)
跟我交流,向我提問:
歡迎關注: