ALDS1_8_C:Binary Search Tree III 二叉搜索树的删除

二叉搜索树的删除操作

题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_8_C

比之前面的两题,再加上删除的操作。

现在假设已经有了一颗二叉搜索树,然后我想要删除一个节点z;那么有以下三种情况

case 1:  z没有子树,即z为叶子节点

case 2:  z只有一颗子树,即只有左子树或只有右子树

case 3:  z既有左子树又有右子树

对于case1是最简单的,直接把z->parent节点的儿子节点赋NIL就可以了;

对于case2,只要把z->parent的儿子赋为z的子树,把z的子树的parent节点赋为z->parent即可;

对于case3,比较复杂,因为BST满足左子树所有值都小于根节点;右子树所有值都大于根节点。所以我们需要找到z节点的 左子树中的最大值 或者 右子树中的最小值。也就是左子树中的最右节点 或者 右子树中的最小节点。比如说x;然后我们只要把x删除(同case1),然后把z的值换成x的值即可。原因很简单,因为x是左子树中的最大值,所以把它作为新的根节点既可以满足x大于所有左子树的值,又可以满足小于所有右子树的值。对于右子树中的最小值也是同理。

这一部分的实现代码如下:(具体实现中把case1和2归为了一类)

node *nextnode(node *x){//找右子树的最小值
	node *z=x->right;
	while(z->left!=NIL){
		z=z->left;
	}
	return z;
}

void denode(node *z){
	node *x,*y;//y表示即将被删除的节点
	if(z->left==NIL||z->right==NIL) y=z;//case1或者case2
	else y=nextnode(z);//如果是case3,要删除的节点就是右子树的最左节点了
	if(y->left!=NIL) x=y->left;//x仅用来标识待删除节点的子树
	else x=y->right;
	if(x!=NIL) x->parent=y->parent;
	if(y->parent==NIL) root=x;
	else{
		if(y==y->parent->left) y->parent->left=x;
		else y->parent->right=x;
	}
	if(y!=z) z->num=y->num;
	delete y;
	return ;
}

在实现过程中,需要考虑到根节点的问题。

全部代码实现如下:

#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

struct node{
	int num;
	node *parent,*left,*right;
};
node *root,*NIL;


node *nextnode(node *x){//找右子树的最小值
	node *z=x->right;
	while(z->left!=NIL){
		z=z->left;
	}
	return z;
}

void denode(node *z){
	node *x,*y;//y表示即将被删除的节点
	if(z->left==NIL||z->right==NIL) y=z;//case1或者case2
	else y=nextnode(z);//如果是case3,要删除的节点就是右子树的最左节点了
	if(y->left!=NIL) x=y->left;//x仅用来标识待删除节点的子树
	else x=y->right;
	if(x!=NIL) x->parent=y->parent;
	if(y->parent==NIL) root=x;
	else{
		if(y==y->parent->left) y->parent->left=x;
		else y->parent->right=x;
	}
	if(y!=z) z->num=y->num;
	delete y;
	return ;
}

node *find(int a){
	node *x=root;
	while(x!=NIL){
		if(x->num<a) x=x->right;
		else if(x->num>a) x=x->left;
		else return x;
	}
	return NIL;
}

void print_inorder(node *x){
	if(x==NIL) return ;
	print_inorder(x->left);
	printf(" %d",x->num);
	print_inorder(x->right);
	return ;
}

void print_preorder(node *x){
	if(x==NIL) return ;
	printf(" %d",x->num);
	print_preorder(x->left);
	print_preorder(x->right);
	return ;
}

void insert(int a){
	node *x=root,*y=NIL;
	node *z=new node();
	z->num=a;z->left=NIL;z->right=NIL;
	while(x!=NIL){
		y=x;
		if(z->num < x->num) x=x->left;
		else x=x->right;
	}
	z->parent=y;
	if(y==NIL) root=z;
	else {
		if(z->num < y->num) y->left=z;
		else y->right=z;
	}
	return ;
}

int main(){
	int n;
	cin>>n;
	string s;
	node *f;
	int a;
	for(int i=0;i<n;i++){
		cin>>s;
		if(s[0]=='i') cin>>a,insert(a);
		else if(s[0]=='p'){
			print_inorder(root);
			printf("\n");
			print_preorder(root);
			printf("\n");
		}
		else if(s[0]=='f'){
			cin>>a;
			f=find(a);
			if(f==NIL) printf("no\n");
			else printf("yes\n");
		}
		else{
			cin>>a;
			denode(find(a));
		}
	}
	return 0;
}

错点:

1.要加上对根节点情况的考虑;

2.AOJ的测试数据比较坑,这题的测试数据,在case3中只能选择右子树中的最左节点,不能选择左子树中的最右节点。

3.对于查找nextnode节点的函数还有疑惑:

// 树的最小值
Node *treeMinimum(Node * x) {
	while (x->left != NIL)
		x = x->left;
	return x;
}

// case 3 ,搜索后一个结点
Node *treeSuccessor(Node *x) {
	if (x->right != NIL)
		return treeMinimum(x->right);

	Node *y = x->parent;
	while (y != NIL && x == y->right) {
		x = y;
		x = y->parent;
	}
	return y;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值