数据结构之二叉查找树的建立遍历删除

本文详细介绍了二叉查找树的删除操作实现方法,包括不同情况下的处理逻辑及代码实现。针对结点的不同子树状况提供了具体的解决方案。

二叉查找树建立,遍历,查找元素很容易实现。我主要写写删除过程。

二叉查找树结点的删除分几种情况:

如果结点是一片树叶,那么直接删除即可。如果结点有一个儿子,则该节点可以在其父节点调整指针绕过该节点后被删除。如果结点有两个儿子,一般的删除方法是用其右子树的最小的数据代替该节点,并删除那个结点。因为最小的那个结点不可能有左儿子,所以第二次删除很容易实现。

代码如下,写的不太好,见笑了敲打

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef int DataType;
typedef struct node
{
	DataType data;
	struct node *lchild, *rchild;
}BinTree, *Tree;
// 添加结点
Tree Add_New_Node(DataType data)
{
	Tree NewNode = (Tree)malloc(sizeof(BinTree));
	memset(NewNode, 0, sizeof(BinTree));
	NewNode->data = data;
	return NewNode;
}
// 二叉查找树的插入操作
Tree Insert(Tree root, DataType num)
{
	if (root == NULL)
	{
		root = Add_New_Node(num);
	}
	else if (num > root->data)
	{
		root->rchild = Insert(root->rchild, num);
	}
	else if (num < root->data)
	{
		root->lchild = Insert(root->lchild, num);
	}
	return root;
}
// 根据关键字找到该结点并返回该节点的地址
Tree Find(Tree root, DataType key)
{
	if (root == NULL)
		return NULL;
	if (key < root->data)
		return Find(root->lchild, key);
	else if (key > root->data)
		return Find(root->rchild, key);
	else
		return root;
}
// 在二叉查找树树中找到最小的结点的值(递归)
Tree FindMin(Tree root)
{
	if (root == NULL)
		return NULL;
	if (root->lchild == NULL)
		return root;
	else
		return FindMin(root->lchild);
}
// 在二叉查找树树中找到最大的结点的值(迭代)
Tree FindMax(Tree root)
{
	if (root != NULL)
	{
		while (root->rchild != NULL)
			root = root->rchild;
	}
	return root;
}
// 找到关键字的父节点并返回它本身的地址和父节点的地址,以及其左右子树对应关系
Tree FindNodeAndPos(Tree root, DataType key, Tree *flag,int *sign)
{
	Tree p = root;
	if (p == NULL)
		return NULL;
	while (p != NULL)
	{
		if (key < p->data)
		{
			*sign = 1;
			*flag = p;
			p = p->lchild;
		}
		else if (key > p->data)
		{
			*sign = 0;
			*flag = p;
			p = p->rchild;
		}
		else
			return p;
	}
	return NULL;
}
// 删除的结点有1个或两个结点
void Delete_A_Node_With_One_Child(Tree Parent,Tree Dest,int Pos)
{
	if (Parent == NULL || Dest == NULL)
		return;
	// 左子树为空右子树不为空
	if (Dest->lchild == NULL && Dest->rchild != NULL)
	{
		if (1 == Pos)
			Parent->lchild = Dest->rchild;
		else
			Parent->rchild = Dest->rchild;
	}
	// 左子树不为空右子树为空
	else if (Dest->lchild != NULL && Dest->rchild == NULL)
	{
		if (1 == Pos)
			Parent->lchild = Dest->lchild;
		else
			Parent->rchild = Dest->lchild;
	}
	// 左右子树均为空
	else
	{
		if (1 == Pos)
			Parent->lchild = NULL;
		else
			Parent->rchild = NULL;
	}
	free(Dest);
}
// 删除函数
void Delete_Node_With_Pos(Tree root, DataType key)
{
	// Parent保存待删除结点的父节点的指针 Dest保存待删除节点的指针
	Tree Parent = NULL, Dest = NULL;
	// Pos标记待删除结点与它的父节点的左右关系,定义 '1'为左 '0'为右
	int Pos = 0;
	// 当待删除的结点为根节点时
	if (root->data == key)
	{
		// Cur保存当前结点的地址 temp保存当前结点右子树中最小的结点的地址
		Tree Cur = Dest, temp = FindMin(root->rchild);
		// 右子树删完了再删左子树
		if (root->rchild!=NULL)
			temp = FindMin(root->rchild);
		else
			temp=FindMin(root->lchild);
		int nData = temp->data;
		Dest = FindNodeAndPos(root, nData, &Parent, &Pos);
		Delete_A_Node_With_One_Child(Parent, Dest, Pos);
		root->data = nData;
	}
	else
	{
		Parent = NULL, Dest = NULL;
		Pos = 0;
		Dest = FindNodeAndPos(root, key, &Parent, &Pos);
		if (Dest == NULL)
		{
			printf("没有该结点,删除失败!\n");
			return;
		}
		// 当待删除结点没有左右子树时
		if (Dest->lchild == NULL && Dest->rchild == NULL)
			Delete_A_Node_With_One_Child(Parent, Dest, Pos);
		// 当待删除结点左右子树均存在时
		else if (Dest->lchild!=NULL && Dest->rchild!=NULL)
		{
			Tree Cur = Dest, temp = FindMin(Dest->rchild);
			int nData = temp->data;
			Parent = NULL, Dest = NULL;
			Pos = 0;
			Dest = FindNodeAndPos(root, nData, &Parent, &Pos);
			Delete_A_Node_With_One_Child(Parent, Dest, Pos);
			Cur->data = nData;
		}
		// 当待删除结点只有一个子树时
		else
			Delete_A_Node_With_One_Child(Parent, Dest, Pos);
	}
}
// 清空整个树
Tree MakeEmpty(Tree root)
{
	if (root != NULL)
	{
		MakeEmpty(root->lchild);
		MakeEmpty(root->rchild);
		free(root);
	}
	return NULL;
}
// 前序遍历
void PreOrder(Tree root)
{
	if (root != NULL)
	{
		printf("%d ", root->data);
		PreOrder(root->lchild);
		PreOrder(root->rchild);
	}
}
// 中序遍历
void InOrder(Tree root)
{
	if (root != NULL)
	{
		InOrder(root->lchild);
		printf("%d ", root->data);
		InOrder(root->rchild);
	}
}
// 后序遍历
void PostOrder(Tree root)
{
	if (root != NULL)
	{
		PostOrder(root->lchild);
		PostOrder(root->rchild);
		printf("%d ", root->data);
	}
}
// 以三种遍历方式打印出所有结点
void Print(Tree root)
{
	printf("前序遍历: ");
	PreOrder(root);
	printf("\n");
	printf("中序遍历: ");
	InOrder(root);
	printf("\n");
	printf("后序遍历: ");
	PostOrder(root);
	printf("\n");
}
int main()
{
	Tree root = NULL;

	for (int i = 0; i < 10; i++)
	{
		root = Insert(root, rand() % 100);
	}

	root = Insert(root, 45);

	Print(root);

	printf("\n删除一个结点后\n\n");

	Delete_Node_With_Pos(root, 58);

	Print(root);

	printf("\n");

	root = MakeEmpty(root);

	system("pause");
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值