二叉搜索树中删除某一结点函数的另外一种实现

在上一篇关于二叉搜索树的笔记中,我自己实现了几个常用的有关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;
}


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