二叉排序樹刪除操作的幾種情況
-
要刪除的結點在二叉排序樹中是葉子結點:
則可以直接刪除,因為刪除它們對於整棵樹來說,其他節點的結構並不受到影響
-
要刪除的結點只有左子樹或者右子樹:
刪除結點后,將它的左子樹或右子樹移動到刪除結點的位置即可(子承父業)
-
要刪除的結點既有左子樹又有右子樹:
簡單的想法:讓刪除結點的左子樹成為刪除結點的雙親的左子樹,然后將刪除結點的右子樹所有結點進行重新插入
更好的算法:在刪除的結點的左右子樹中尋找有一個結點來代替刪除結點(與其最接近的兩個數之一),然后再刪除這個用來替換的結點(這個用來替換的結點 一定是一個葉子結點或者只有一個左孩子)
二叉排序樹刪除算法源碼
//若二叉排序樹中存在關鍵字等於key的數據元素,則刪除該數據元素並返回TURE;否則返回FALSE
//算法中采用了遞歸的實現方式
status DeleteBST(BiTree* T, int key){
if(!*T) //不存在關鍵字等於key的數據元素
return false;
else{
if (key == (*T)->data) //找到關鍵字等於key的數據元素
return Delete(T);
else if (key<(*T)->data)
//這里T是二叉樹的指針,*T得到根節點對象,&表示以引用傳遞參數(可以對原對象進行修改)(引用修飾整體)
return DeleteBST(&(*T)->lchild,key);
else
return DeleteBST(&(*T)->rchild,key);
}
}
可以看出,其實二叉排序樹的刪除算法的實現方式和二叉排序樹的查找算法幾乎完全相同,唯一的不同就是使用了Delete函數,對當前結點進行刪除操作。
Delete函數的具體實現
//二叉排序樹中刪除結點p,並重新連接它的左子樹或右子樹
status Delete(BiTree* p){
BiTree q, s;
//右子樹為空則只需要連接它的左子樹
if ((*p)->rchild==NULL){ //*p得到根節點
//free根節點,保留左子樹
q = *p; *p = (*p)->lchild; free(q);
}
else if ((*p)->lchild==NULL){ //只需要連接它的右子樹
q = *p; *p = (*p)->rchild; free(q);
}
//左右子樹均非空
else{
q = *p; s = (*p)->lchild;
while (s->rchild){
//轉左,然后向右到盡頭(找到待刪除結點的直接前驅)(也可以選擇找它的直接后繼)
q = s; s = s->rchild;
}
//上面while循環的結果為:s為直接前驅,q為s的雙親
(*p)->data = s->data;
//以下就是在刪除s結點(這兩種情況會在下文進行舉例說明)
if (q != *p)
q->rchild = s->lchild;
//如果第一個s就沒有右孩子的話,就會有(q = *p),進而出現這種情況
else
q->lchild = s->lchild;
free(s);
}
return true;
}
Delete函數中 q!=*p 的情況
-
如上圖所示,將p指向的結點用s指向的結點覆蓋
-
之后,按照上文中代碼的邏輯,將s結點的左孩子賦值給q結點的右孩子
-
操作的結果如下圖所示:
Delete函數中 q=*p 的情況
-
如上圖所示,將p指向的結點用s指向的結點覆蓋
-
之后,按照上文中代碼的邏輯,將s結點的左孩子賦值給q結點的左孩子
-
操作的結果如下圖所示:
