二叉搜索樹中刪除某一結點函數的另外一種實現

在上一篇關於二叉搜索樹的筆記中,我自己實現了幾個常用的有關BST的成員函數。其中刪除指定結點的函數十分複雜,還要考慮被刪結點的三種可能的情況。

其實,還有另外一種思路來實現刪除結點這一操作。

假設我們要刪除的結點是u,可以發現,如果被刪結點u沒有左子樹,或者沒有右子樹,或者左右子樹都沒有的話,實際編碼過程中,被釋放的結點d就是結點u本身。

但是如果結點u的左右子樹均存在,實際編碼過程中,結點u改變的只是自身的關鍵值u->key,沒有被真正釋放。真正被釋放的結點d是結點u的右子樹中值最小的結點

(當然也可以是左子樹中值最大的結點,完全取決與你想如何實現)。因此,我們把關注點從結點u是否存在左右子樹,轉移到真正被釋放的結點d到底是什麼。

這就是實現刪除某一結點函數的新思路:

一、找到實際需要刪除並釋放的結點d

如果被刪結點u沒有左子樹,或者沒有右子樹,或者左右子樹都沒有,d = u

如果被刪結點u左右子樹均存在,d = u的右子樹中值最小的結點

二、找到結點d 的父結點f  與 d 的子結點s

三、重置結點f 的子結點

f == NULL , 說明結點d爲根結點,根結點root = s(結點u左右子樹均存在時,d 的父結點f 一定存在,不會有這種情況)

否則將f 的子結點變爲 s

四、釋放結點d

如果結點u左右子樹均存在(等價於d != u), u->key = d->key

最後釋放結點d

參考代碼如下:

//刪除指定結點
void DeleteNode(tree_node &root, tree_node u)
{
	tree_node d; //結點d存放實際需要釋放的結點
	tree_node f = NULL; //結點f存放結點d的父結點
	tree_node s; //結點s存放結點d的子結點
	
	//確定結點d
	if (u->left == NULL || u->right == NULL) d = u;
	else {
		d = u->right;
		while (d->left != NULL) d = d->left;
	}
	//確定結點s
	if (d->left != NULL) {
		s = d->left;
	} else {
		s = d->right;    //此時結點s也可能爲NULL
	}
	//確定結點f
	tree_node x = root;
	while (x != NULL && x != d) {
		f = x;
		if (d->key < x->key)
			x = x->left;
		else
			x = x->right;
	}
	if (x == NULL) return;  //要刪除的結點不存在
	//刪除並釋放結點d
	if (f == NULL) root = s; //可以證明,這種情況下,結點u不可能同時存在左右子樹
	else if (d == f->left)
		f->left = s;
	else
		f->right = s;
	
	if (d != u)
		u->key = d->key;  //結點u左右子樹均存在
	free(d);
	
	return;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章