输入一串整数,构造其对应的二叉排序树,并在其上删除任意一个值等于用户输入值的结点。

输入一串整数,构造其对应的二叉排序树,
并在其上删除任意一个值等于用户输入值的结点。 

功能有:1构造平衡二叉树,2查找平衡二叉树删除值,3在二叉树上删除该值同时调整平衡二叉树,4最后中序输出删除值后,调整了的平衡二叉树

其中难点:删除 平衡二叉树指定值 分为以下三种情况:

1.

1.1(如果删除的是根结点):只有左子树:删除1图根5,或2图根6的结点,只需将根结点修改为指向数值为3的结点。

1.2中间结点,

1.2.1对应1图删除值为3结点,可以提前获取一个前结点pre指向5结点,删除3结点只需让5结点指向2

1.2.2对应2图删除值为3结点,首先向右再一直向左(不为NULL)找到后继结点,然后换掉值,删除肯定没有左子树的后继结点。

扫描二维码关注公众号,回复: 13391575 查看本文章

 2.只有右子树:

2.1同样图1删除根5,只需将根结点指向6即可,图2删除根6只需修改根节点指向9即可。

2.2删除图1的6类似的可以提前获取一个前结点pre指向5结点,删除6结点只需让5结点指向7,图2删除9,需寻找到9的后继结点8(向右然后一直向左直到左孩子为NULL),然后换掉值,最后后继结点肯定没有左孩子,就变成了只有右子树(或没有子树)的情况。

3.左右子树都存在的情况:就转化为了 求前驱或者后继结点了,

 

summary:

综上所述,

一,根结点:

1.如果只有左(右)子树就直接让根结点变化指向左(右)子树首结点

 2.左右子树都存在,就找到前驱或者后继(其一便可),然后与前驱或后继结点交换值,由于前驱结点一定没有右子树,后继结点没有左子树,就转化为了第一种情况(为方面可设一个前结点)。

一,中间结点:

1.如果只有左(右)子树就直接让前结点(设一个保存)变化指向左(右)子树首结点

 2.左右子树都存在,就找到前驱或者后继(其一便可),然后与前驱或后继结点交换值,由于前驱结点一定没有右子树,后继结点没有左子树,就转化为了第一种情况(为方面可设一个前结点)。

        头结点和中间结点第2种情况一样处理可以合并。

以下是代码:

一:删除指定值的平衡二叉树结点代码(完整代码在最后):

void delete_node(blink root,int data)
{
		//采用 后者
		blink q;//保存 要删除结点
		blink pre;//获取要删除结点的前结点
		q = search_node(root,&pre,data);
		if(q != NULL)
		{
			
			if(q == root)//当要删除的是根节点时 此时根结点 没有 头结点,用头结点法 失效换方法 
			{
				
				if(q->lchild == NULL && q->rchild == NULL)//说明根节点没有子树了 
				{
					q = NULL;//置为空 
					free(q);//释放
					return;
				}
				else if(q->lchild != NULL && q->rchild == NULL)//说明根结点只有左子树 
				{
					//保存要删除的根 结点  
					blink s = q;
					root = q->lchild;//修改根结点指向 左子树的首结点
					s = NULL;//置为空 
					free(s);//释放
					return;
				}
				else if(q->lchild == NULL && q->rchild != NULL)//说明根结点 只有右子树 
				{
					//保存要删除的根 结点 
					blink s = q;
					root = q->rchild;//修改根结点指向 右子树的首结点
					s = NULL;//置为空 
					free(s);//释放
					return;
				}
				else;
			}
			
			if(q->lchild == NULL && q->rchild == NULL)//说明q已经是叶子结点了不用找 
			{
				q = NULL;//置为空 
				free(q);//释放
				return;
			}
			else if(q->lchild != NULL && q->rchild == NULL)//说明q只有左子树 
			{
				if(pre->lchild == q)//如果q是其前指针的左孩子 
				{
					pre->lchild = q->lchild;
				}
				else//是右孩子 
				{
					pre->rchild = q->lchild;
				}	
					q = NULL;//置为空 
					free(q);//释放 
					return;//返回根结点p 
			}
				
			else if(q->lchild == NULL && q->rchild != NULL)//说明q只有右子树 
			{
				if(pre->lchild == q)//如果q是其前指针的左孩子 
				{
					pre->lchild = q->rchild;
				}
				else//是右孩子 
				{
					pre->rchild = q->rchild;
				}
				
				q = NULL;//置为空 
				free(q);//释放
				return;
			}
				//左右子树都有的情况 
				//一种方法 找到 该结点(根结点先向左,然后一直右,不为空)直接前驱替换,再类似于前面情况删除(中序 后继前驱 左右子树 必定有一个子树为空) 
				//另一方法 找到 该结点(根结点先向右,然后一直左,不为空)直接后继替换,再类于前面情况删除(中序 后继前驱 左右子树 必定有一个子树为空)
			else
			{ 
				//在右子树上搜索 前驱 s 
				blink s = q->rchild;
				blink s_pre = q;//保存前驱s的 前结点 
				while(s->lchild != NULL)
				{
					s_pre = s;s = s->lchild;
				}
				//找到后 替换两个结点的值 
				int t = 0;
				//替换 
				t = q->data;
				q->data = s->data;
				s->data = t;
				//现在要删除的结点 变成了s,且s已经变成了 左子树为空的情况
					
				if(s_pre == q)//如果前 结点是根结点的话 
				{
					s_pre->rchild = s->rchild;
					s = NULL;
					free(s);
				}
				
				else
				{
					s_pre->lchild = s->rchild;
					s = NULL;
					free(s);
				}
			}
		}
		
	return;
}

 二:创建平衡二叉树结点代码(完整代码在最后):

//构造其对应的二叉排序树(递归)
blink add(blink bt,char in)
{
	if(bt == NULL)
	{
		bt = (blink)malloc(sizeof(bnode));
		bt->data = in;
		bt->lchild = bt->rchild = NULL;
	}
	//二叉排序数 的构建 过程,大于根结点 在左边否则右边 
	else
	{
		if(in < bt->data)
		{
			bt->lchild = add(bt->lchild,in);
		}
		else
		{
			bt->rchild = add(bt->rchild,in);
		}
	}
	return bt;
}

三:查找平衡二叉树指定值结点的代码(完整代码在最后):

//查找等于data值的结点 
blink search_node(blink root,blink *pre,int elem)
{
	blink p = root;
	*pre = root;
	//先找到一个有该值的结点 
	while(p != NULL)//p得有结点才进入循环 
	{
		//平衡二叉树 左比根值小 右比根值大 
		
		if(p->data < elem)//elem若大,往右走 
		{
			*pre = p;
			p = p->rchild;
		}
		else if(p->data > elem)//elem若小,往左走
		{
			*pre = p;
			p = p->lchild;
		}
		else//data值等于了根结点的值 
		{
			break;
		}
	}
	 
	if(p == NULL)
	{
		printf("不存在该值的结点");
		return NULL;
	}
	else
	{
		return p;
	}
}

四:中序遍历平衡二叉树代码(完整代码在最后):

//中序遍历 
void inorder(blink bt)
{
	/*
	依照test_one
	结果 为 abcdefg(当然这里 也可以发现,中序遍历 二叉排序树实际是 递增序列) 
	*/
	
	if(bt != NULL)//中序 左根右 
	{
		inorder(bt->lchild); //左
		printf("%d",bt->data);//根
		inorder(bt->rchild); //右 
	}
	
	return;
}

完整代码CODE:

/*
输入一串整数,构造其对应的二叉排序树,
并在其上删除任意一个值等于用户输入值的结点。 
*/

#include "stdio.h"//包含 getchar() scanf() printf() 
#include "malloc.h"//malloc()动态申请空间 函数

//二叉树 结点 
struct node{
	char data;
	struct node *lchild,*rchild;
}bnode;

typedef struct node * blink;

//构造其对应的二叉排序树(递归)
blink add(blink bt,char in)
{
	if(bt == NULL)
	{
		bt = (blink)malloc(sizeof(bnode));
		bt->data = in;
		bt->lchild = bt->rchild = NULL;
	}
	//二叉排序数 的构建 过程,大于根结点 在左边否则右边 
	else
	{
		if(in < bt->data)
		{
			bt->lchild = add(bt->lchild,in);
		}
		else
		{
			bt->rchild = add(bt->rchild,in);
		}
	}
	return bt;
}

//查找等于data值的结点 
blink search_node(blink root,blink *pre,int elem)
{
	blink p = root;
	*pre = root;
	//先找到一个有该值的结点 
	while(p != NULL)//p得有结点才进入循环 
	{
		//平衡二叉树 左比根值小 右比根值大 
		
		if(p->data < elem)//elem若大,往右走 
		{
			*pre = p;
			p = p->rchild;
		}
		else if(p->data > elem)//elem若小,往左走
		{
			*pre = p;
			p = p->lchild;
		}
		else//data值等于了根结点的值 
		{
			break;
		}
	}
	 
	if(p == NULL)
	{
		printf("不存在该值的结点");
		return NULL;
	}
	else
	{
		return p;
	}
}

void delete_node(blink root,int data)
{
		//采用 后者
		blink q;//保存 要删除结点
		blink pre;//获取要删除结点的前结点
		q = search_node(root,&pre,data);
		if(q != NULL)
		{
			
			if(q == root)//当要删除的是根节点时 此时根结点 没有 头结点,用头结点法 失效换方法 
			{
				
				if(q->lchild == NULL && q->rchild == NULL)//说明根节点没有子树了 
				{
					q = NULL;//置为空 
					free(q);//释放
					return;
				}
				else if(q->lchild != NULL && q->rchild == NULL)//说明根结点只有左子树 
				{
					//保存要删除的根 结点  
					blink s = q;
					root = q->lchild;//修改根结点指向 左子树的首结点
					s = NULL;//置为空 
					free(s);//释放
					return;
				}
				else if(q->lchild == NULL && q->rchild != NULL)//说明根结点 只有右子树 
				{
					//保存要删除的根 结点 
					blink s = q;
					root = q->rchild;//修改根结点指向 右子树的首结点
					s = NULL;//置为空 
					free(s);//释放
					return;
				}
				else;
			}
			
			if(q->lchild == NULL && q->rchild == NULL)//说明q已经是叶子结点了不用找 
			{
				q = NULL;//置为空 
				free(q);//释放
				return;
			}
			else if(q->lchild != NULL && q->rchild == NULL)//说明q只有左子树 
			{
				if(pre->lchild == q)//如果q是其前指针的左孩子 
				{
					pre->lchild = q->lchild;
				}
				else//是右孩子 
				{
					pre->rchild = q->lchild;
				}	
					q = NULL;//置为空 
					free(q);//释放 
					return;//返回根结点p 
			}
				
			else if(q->lchild == NULL && q->rchild != NULL)//说明q只有右子树 
			{
				if(pre->lchild == q)//如果q是其前指针的左孩子 
				{
					pre->lchild = q->rchild;
				}
				else//是右孩子 
				{
					pre->rchild = q->rchild;
				}
				
				q = NULL;//置为空 
				free(q);//释放
				return;
			}
				//左右子树都有的情况 
				//一种方法 找到 该结点(根结点先向左,然后一直右,不为空)直接前驱替换,再类似于前面情况删除(中序 后继前驱 左右子树 必定有一个子树为空) 
				//另一方法 找到 该结点(根结点先向右,然后一直左,不为空)直接后继替换,再类于前面情况删除(中序 后继前驱 左右子树 必定有一个子树为空)
			else
			{ 
				//在右子树上搜索 前驱 s 
				blink s = q->rchild;
				blink s_pre = q;//保存前驱s的 前结点 
				while(s->lchild != NULL)
				{
					s_pre = s;s = s->lchild;
				}
				//找到后 替换两个结点的值 
				int t = 0;
				//替换 
				t = q->data;
				q->data = s->data;
				s->data = t;
				//现在要删除的结点 变成了s,且s已经变成了 左子树为空的情况
					
				if(s_pre == q)//如果前 结点是根结点的话 
				{
					s_pre->rchild = s->rchild;
					s = NULL;
					free(s);
				}
				
				else
				{
					s_pre->lchild = s->rchild;
					s = NULL;
					free(s);
				}
			}
		}
		
	return;
}

//中序遍历 
void inorder(blink bt);
int main()
{
	blink root = NULL;//根 结点
	int i = 0;
	int x = 0;
	
	//建树 
	printf("以-99结束输入:\n");
	while(1)
	{
		scanf("%d",&x);
		if(x == -99)//结束标识 
		{
			break;
		}
		root = add(root,x);// 开始建树
	}
	printf("创建的树(中序)\n");
	inorder(root);//中序 打印 
	
	//删除 
	printf("输入要删除的包含那个值的结点:");
	int del = 0;
	scanf("%d",&del);
	delete_node(root,del);
	
	printf("删除某结点后的树(中序)\n");
	inorder(root);//中序 打印 
	printf("\n");
	
	return 0;
}
//中序遍历 
void inorder(blink bt)
{
	/*
	依照test_one
	结果 为 abcdefg(当然这里 也可以发现,中序遍历 二叉排序树实际是 递增序列) 
	*/
	
	if(bt != NULL)//中序 左根右 
	{
		inorder(bt->lchild); //左
		printf("%d",bt->data);//根
		inorder(bt->rchild); //右 
	}
	
	return;
}

result:

删除左右都有子树的中间结点

 删除只有右子树的中间结点:

 删除根结点:

 

猜你喜欢

转载自blog.csdn.net/qq_47991812/article/details/121448404
今日推荐