在二叉排序树中删除一个结点

在二叉排序树中删除一个结点

在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须先把被删除结点从存储二叉排序树的链表上摘下,将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。

二叉排序树的删除要考虑三种情况:

  1. 若被删除结点x是叶子结点,则直接删除,并修改x的父结点的指针为NULL;
  2. 若被删除结点x只有一棵左子树或右子树,则让x的子树成为x父结点的子树,替代x的位置;
  3. 若被删除结点x有左、右两棵子树,则用另一结点替代被删除的结点x:x右子树的最小元素或者x左子树的最大元素,然后删除这个替代结点(因为在二叉排序树中右子树的最小元素、左子树的最大元素要么是叶子结点,要么只有一棵左子树或右子树,一定不会同时有左、右子树,这样就转换成了第一或第二种情况);

如有谬误或者不足还请批评指正!

BSTree Delete(BSTree BST, int x)
{
	BSTNode *p;
	if (BST == NULL) //如果树为空直接返回
		return NULL;
	else if (x < BST->data) //小于则左子树递归删除
		BST->lchild = Delete(BST->lchild, x);
	else if (x > BST->data) //大于则右子树递归删除
		BST->rchild = Delete(BST->rchild, x);
	else //等于则找到了要删除的结点
	{
		//如果被删除的结点有左、右两个孩子结点
		if (BST->lchild && BST->rchild)
		{
			//找到右子树的最小元素
			p = FindMin(BST->rchild);
			//替代被删除的结点
			BST->data = p->data;
			//在被删除结点的右子树中删除刚才找到的右子树的最小元素
			BST->rchild = Delete(BST->rchild, p->data);
		}
		//如果被删除结点只有一个孩子结点或没有孩子结点
		else
		{
			p = BST;
			if (BST->lchild == NULL) //有右孩子结点或没有孩子结点
				BST = BST->rchild;
			else if (BST->rchild == NULL) //有左孩子结点或没有孩子结点
				BST = BST->lchild;
			free(p); //释放结点
		}
	}
	return BST;
}

BSTree FindMin(BSTree BST)
{
	if(BST == NULL) //树为空直接放回
		return NULL;
	else if(BST->lchild == NULL) //找到最左叶子结点并返回
		return BST;
	else
		return FindMin(BST->lchild); //沿左分支继续递归查找
}

强烈推荐浙江大学的数据结构课程,讲的非常好!

  • 15
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是二叉排序树删除操作的代码,包含了上述三种情况的处理: ``` // 删除二叉排序树值为data的节点 void deleteNode(BSTree &root, int data) { BSTree p = root, f = nullptr; // p指向要删除结点,f指向p的双亲结点 while (p != nullptr && p->data != data) { // 查找要删除结点 f = p; // 记录当前结点的双亲结点 if (data < p->data) { p = p->left; } else { p = p->right; } } if (p == nullptr) { // 没有找到要删除结点 return; } if (p->left == nullptr && p->right == nullptr) { // 要删除结点为叶子结点 if (p == root) { // 要删除结点为根结点 root = nullptr; } else if (p == f->left) { // 要删除结点为f的左子结点 f->left = nullptr; } else { // 要删除结点为f的右子结点 f->right = nullptr; } delete p; } else if (p->left != nullptr && p->right == nullptr) { // 要删除结点只有左子树 if (p == root) { // 要删除结点为根结点 root = p->left; } else if (p == f->left) { // 要删除结点为f的左子结点 f->left = p->left; } else { // 要删除结点为f的右子结点 f->right = p->left; } delete p; } else if (p->left == nullptr && p->right != nullptr) { // 要删除结点只有右子树 if (p == root) { // 要删除结点为根结点 root = p->right; } else if (p == f->left) { // 要删除结点为f的左子结点 f->left = p->right; } else { // 要删除结点为f的右子结点 f->right = p->right; } delete p; } else { // 要删除结点既有左子树又有右子树 BSTree q = p->left, s = p; // q指向p的左子树,s指向p while (q->right != nullptr) { // 查找p的左子树最大的结点,即q的右子树最右下角的结点 s = q; q = q->right; } p->data = q->data; // 用q的值替换p的值 if (s == p) { // q是p的左孩子 s->left = q->left; } else { // q是p的左孩子的右子孙 s->right = q->left; } delete q; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值