【数据结构】搜索二叉树

具有什么特征的树是一棵二叉搜索树:

  • 空树
  • 若左右子树存在,左子树上的所有结点都小于根节点的值,右子树上的所有结点都大于根结点的值;左右子树也满足以上特征

根据以上特征发现二叉搜索树的中序遍历是有序的
在这里插入图片描述
中序遍历:1 2 3 4 5 6 7 8 9 10

查找

如果根结点不为空,则进行一下判断:

  • 如果根命中,表示找到了
  • 如果所要找的值小于根的值,去其左子树找
  • 如果所要找的只大于根的值,去其右子树找

当走到空结点,表示没能找到需要找的结点,该结点不在该二叉搜索树中

//找到了返回0,没找到返回-1
int Search(Node *root, Key key)
{
	Node *cur = root;

	while (cur != NULL)
	{
		if (cur->key == key)
		{
			return 0;
		}
		else if (cur->key > key)
		{
			cur = cur->left;
		}
		else
		{
			cur = cur->right;
		}
	}
	return -1;
}
  • 递归写法
int Search_R(Node *root, Key key)
{
	if (root == NULL) {
		// 空树
		return -1;
	}
	if (key == root->key) {
		return 0;
	}
	else if (key < root->key) {
		return Search_R(root->left, key);
	}
	else {
		return Search_R(root->right, key);
	}
}

插入

由于搜索二叉树要保证不存在重复元素的存在,所以在进行插入之前先要进行依次查找

  • 如果元素存在,返回-1代表插入失败
  • 如果不存在,根据查找算法找到空结点的上一个叶子结点就是插入结点的双亲,再根据二叉搜索树的特点来判断是双亲的左孩子还是右孩子即可,插入成功返回0
  • 空树直接进行插入,此时要注意是对指向搜索二叉树的第一个结点地址的指针的值进行修改,故要传二级指针
int Insert(Node **proot, Key key)
{
	Node *cur = *proot;
	Node *prev = NULL;
	Node *newNode = NULL;

	while (cur != NULL)
	{
		if (cur->key == key)
		{
			printf("插入失败\n");
			return -1;//不再重复插入
		}
		prev = cur;
		if (cur->key > key)
		{
			cur = cur->left;
		}
		else
		{
			cur = cur->right;
		}
	}
	newNode = CreateNode(key);
	//空树直接插入
	if (*proot == NULL)
	{
		*proot = newNode;//不能写成cur = newNode
	}

	if (key < prev->key)
	{
		prev->left = newNode;
	}
	else
	{
		prev->right = newNode;
	}
	printf("插入成功\n");
	return 0;
}
  • 递归写法
int Insert_R(Node **proot, Key key)
{
	if (*proot == NULL) {
		*proot = CreateNode(key);
		return 0;
	}

	if (key == (*proot)->key) {
		return -1;
	}

	if (key < (*proot)->key) {
		return Insert_R(&(*proot)->left, key);
	}
	else {
		return Insert_R(&(*proot)->right, key);
	}
}

删除

删除也要先做查找,所以空树直接返回,所要删除结点不在树中也返回,如果需要删除,有以下情况

cur为所要删除结点

  • 左子树为空,右子树存在
    在这里插入图片描述
  • 右子树为空,左子树存在
    在这里插入图片描述
  • 左右子树都存在
    采用替换删除法,找到左子树里面值最大的那个结点,用该值替换掉所要删除结点的值
    在这里插入图片描述
  • 左右子树不存在
    这种情况可以合并到第1或第2种情况当中去
int Remove(Node **proot, Key key)
{
	Node *cur = *proot;
	Node *prev = NULL;
	Node *del = NULL;
	Node *delParent = NULL;

	while (cur != NULL)
	{
		if (cur->key == key)
		{
			if (cur->left != NULL && cur->right != NULL)
			{
				del = cur->left;
				delParent = cur;
				while (del->right != NULL)
				{
					delParent = del;
					del = del->right;
				}
				cur->key = del->key;
				if (delParent == cur)
				{
					cur->left = del->left;
				}
				else
				{
					delParent->right = NULL;
				}
				free(del);
				printf("删除成功\n");
				return 0;
			}
			else if (cur->left == NULL && cur->right != NULL)
			{
				if (*proot == NULL)
				{
					*proot = cur->right;
				}
				else if (key < prev->key)
				{
					prev->left = cur->right;
				}
				else
				{
					prev->right = cur->right;
				}
				free(cur);
				printf("删除成功\n");
				return 0;
			}
			else
			{
				if (*proot == NULL)
				{
					*proot = cur->left;
				}
				else if (key < prev->key)
				{
					prev->left = cur->left;
				}
				else
				{
					prev->right = cur->left;
				}
				free(cur);
				printf("删除成功\n");
				return 0;
			}						
		}
		prev = cur;
		if (cur->key > key)
		{
			cur = cur->left;
		}
		else
		{
			cur = cur->right;
		}
	}
	return -1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值