深入了解二叉搜索树:原理、操作与应用


在这里插入图片描述

二叉搜索树

在这里插入图片描述

形如上图的二叉树就是二叉搜索树,接下来我们来具体阐述一下什么是二叉搜索树。

二叉搜索树的概念:满足左子树的值小于根节点,右子树的值大于根节点的值,这样的树就是二叉搜索树

二叉搜索树的性质:
1.二叉搜索树的中序遍历呈现单调递增的性质。
2.二叉搜索树的每个节点的值都具有唯一性。

二叉搜索树的操作

对于普通的二叉树来说,增删查改没有意义,但是对于二叉搜索树来说增删查改便有了意义,接下来,我们来研究二叉搜索树的增删查改等等一系列操作。
首先我们先定义一个二叉搜索树,二叉搜索树的定义和二叉树的定义相同:

class TreeNode
{
public:
private:
	int _val;
	TreeNode* _left;
	TreeNode* _right;
};
class BST
{
public:
private:
	TreeNode* _root;
};

上面就是二叉搜索树的定义

接下来我们来写一下二叉搜索树的接口,,我们先将其列在BST

class BST
{
public:
	//初始化
	BST();
	//查找
	bool Search(int val);
	bool SearchNode(TreeNode* Node, int val);
	//插入
	void Insert(int val);
	TreeNode* InsertNode(TreeNode* Node, int val);
	//删除
	void Delete(int val);
	TreeNode* AssistDelete(TreeNode* Node, int val);
	TreeNode* FindPrev(TreeNode* root, TreeNode* Node);
	//查找最大值或者最小值
	int GetMin();
	TreeNode* AssistGetMin(TreeNode*Node);
	int GetMax();
	TreeNode* AssistGetMax(TreeNode* Node);
	//后序遍历
	void PostOrder();
	void AssistPostOrder(TreeNode* Node);
	//中序遍历
	void InOrder();
	void AssistInOrder(TreeNode* Node);
	//前序遍历
	void PrevOrder();
	void AssistPrevOrder(TreeNode* Node);
private:
	TreeNode* _root;
};

接下我们一个一个来探讨

1.查找操作

//查找
bool Search(int val);
bool SearchNode(TreeNode* Node, int val);

找到了返回true,没找到返回false
对于普通的二叉树来说我们需要遍历整个树对其进行查找,而且可能二叉树中还有重复值的节点,但是对于二叉搜索树就没有这种麻烦,当我们要搜索一个数时,只需要将这个数和根节点的值进行比较,如果比根节点的数大就递归到右边,如果比根节点的数小就递归左边,不需要整个树都递归。

我们来看看具体代码:

bool BST::Search(int val)
{
	return SearchNode(_root, val);
}
//辅助函数
bool BST::SearchNode(TreeNode* Node, int val)
{
	//找到了nullptr就说明没找到,直接返回false
	if (Node == nullptr)
	{
		return false;
	}
	//判断val的位置,对左子树或者右子树进行递归
	if (Node->_val == val)
	{
		return true;
	}
	else if (val < Node->_val)
	{
		return SearchNode(Node->_left, val);
	}
	else
	{
		return SearchNode(Node->_right, val);
	}
}

2.插入操作

对于普通二叉树来说,插入操作没有意义,因为每一个地方都可以插入,并没有实际意义,但是对于二叉搜索树来说就有意义了,对于二叉搜索树来说,插入操作具有唯一性,可以维护二叉搜索树的排序的性质。

//插入
void Insert(int val);
TreeNode* InsertNode(TreeNode* Node, int val);

查到插入位置然后返回,InsertNode是一个辅助函数。
具体代码:

void BST::Insert(int val)
{
	_root = InsertNode(_root, val);
}
TreeNode* BST::InsertNode(TreeNode* Node, int val)
{
	//当Node==nullptr的时候说明找到了插入的位置
	if (Node == nullptr)
	{
		创造一个新的节点,用val进行初始化
		return new TreeNode(val);//创建一个节点
	}
	//判断递归的范围
	if (Node->_val < val)
	{
		Node->_right = InsertNode(Node->_right, val);
	}
	else if (Node->_val > val)
	{
		Node->_left = InsertNode(Node->_left, val);
	}
	//最后返回Node
	return Node;
}

3.查找最大值或者最小值

//查找最大值或者最小值
int GetMin();
TreeNode* AssistGetMin(TreeNode*Node);
int GetMax();
TreeNode* AssistGetMax(TreeNode* Node);

由于二叉搜索树的特殊性质,左子树的值一定比右子树小,说明最大值一定在右子树的最右边的一个节点上,而最小值一定在左子树的最左边的一个节点上。

我们来看看代码:

//查找最小值
int BST::GetMin()
{
	//根节点为空的时候,说明没有,直接返回INT_MAX
	if (_root == nullptr)
	{
		return INT_MAX;
	}
	//找到最小值的节点
	TreeNode* min = AssistGetMin(_root);
	//返回最小值
	return min->_val;
}
TreeNode* BST::AssistGetMin(TreeNode* Node)
{
	//直接递归左子树,当左子树指向的左边是空的时候直接返回当前节点
	if (Node->_left == nullptr)
	{
		return Node;
	}
	//递归左子树
	return AssistGetMin(Node->_left);
}
//查找最大值
int BST::GetMax()
{
	//同上
	if (_root == nullptr)
	{
		return INT_MAX;
	}
	//找到最大值对应的节点
	TreeNode* max = AssistGetMax(_root);
	//返回最大值
	return max->_val;
}
TreeNode* BST::AssistGetMax(TreeNode* Node)
{
	//判断边界条件
	if (Node->_right == nullptr)
	{
		return Node;
	}
	//递归右子树
	return AssistGetMax(Node->_right);
}

4.删除操作

//删除
void Delete(int val);
TreeNode* AssistDelete(TreeNode* Node, int val);
TreeNode* FindPrev(TreeNode* root, TreeNode* Node);

对于删除操作存在三种情况:
1. 删除的当前节点的左节点和右节点都是nullpt
2. 删除的当前节点的的左节点或者右节点当中存在一个节点,有一个节点是nullpt
3. 删除的当前节点的左节点和右节点都不为nullptr

对于删除操作我们还需要一个函数就是能找到前一个节点的函数,当我们删除了一个节点之后,我们需要找到前一个节点将它与后一个节点连接起来,还需要一个函数就是我们刚刚写的找最大值的函数或者找最小值的函数,这里我们就用找最小值的函数,对于删除的当前节点的左节点和右节点都不为空的时候,我们需要有一个节点来重新构造一下这个二叉搜索树,这里有个技巧,就是我们需要的节点就是当前节点的左子树的最大值的节点或者是右子树的最小值的节点充当本节点。

代码展示:

void BST::Delete(int val)
{
	_root = AssistDelete(_root, val);
}
//找到前一个节点
TreeNode* BST::FindPrev(TreeNode* root, TreeNode* Node)
{
	if (root->_left == Node || root->_right == Node)
	{
		return root;
	}
	if (root->_val < Node->_val)
	{
		FindPrev(root->_right, Node);
	}
	if (root->_val > Node->_val)
	{
		FindPrev(root->_left, Node);
	}
}
//删除操作
TreeNode* BST::AssistDelete(TreeNode* node, int val)
{
	//当node==nullptr说明没有满足条件的删除节点,直接返回nullpr
	if (node == nullptr)
	{
		return node;
	}
	// 找到要删除的节点
	if (val < node->_val)
	{
		node->_left = AssistDelete(node->_left, val);
	}
	else if (val > node->_val)
	{
		node->_right = AssistDelete(node->_right, val);
	}
	//找到了之后进入else进行删除操作
	else
	{
		// 要删除的节点有一个或没有孩子
		if (node->_left == nullptr)
		{
			TreeNode* temp = node->_right;
			delete node;
			return temp;
		}
		else if (node->_right == nullptr)
		{
			TreeNode* temp = node->_left;
			delete node;
			return temp;
		}

		// 要删除的节点有两个孩子
		// 找到要删除节点的后继节点(右子树中的最小节点)
		TreeNode* temp = AssistGetMin(node->_right);
		// 将后继节点的值复制到要删除的节点中
		node->_val = temp->_val;
		// 递归删除后继节点
		node->_right = AssistDelete(node->_right, temp->_val);
	}
	//返回
	return node;
}

5.前序中序后序遍历

	//后序遍历
	void PostOrder();
	void AssistPostOrder(TreeNode* Node);
	//中序遍历
	void InOrder();
	void AssistInOrder(TreeNode* Node);
	//前序遍历
	void PrevOrder();
	void AssistPrevOrder(TreeNode* Node);

和普通二叉树相同

void BST::PostOrder()
{
	AssistPostOrder(_root);
}
void BST::AssistPostOrder(TreeNode* Node)
{
	if (Node == nullptr)
	{
		return;
	}
	AssistPostOrder(Node->_left);
	AssistPostOrder(Node->_right);
	cout << Node->_val << ' ';
}
void BST::InOrder()
{
	AssistInOrder(_root);
}
void BST::AssistInOrder(TreeNode* Node)
{
	if (Node == nullptr)
	{
		return;
	}
	AssistInOrder(Node->_left);
	cout << Node->_val << ' ';
	AssistInOrder(Node->_right);
}
void BST::PrevOrder()
{
	AssistPrevOrder(_root);
}
void BST::AssistPrevOrder(TreeNode* Node)
{
	if (Node == nullptr)
	{
		return;
	}
	cout << Node->_val << ' ';
	AssistPrevOrder(Node->_left);
	AssistPrevOrder(Node->_right);
}

总结

总的来说,二叉搜索树(BST)作为一种重要的数据结构,在计算机科学领域发挥着重要作用。通过其排序性质和高效的搜索、插入和删除操作,二叉搜索树成为了解决各种问题的有力工具。

在本博客中,我们深入探讨了二叉搜索树的概念、性质和操作。我们了解到,二叉搜索树具有自平衡的能力,能够在平均情况下保持较低的时间复杂度。同时,我们也注意到了在极端情况下,二叉搜索树可能会退化为链表,导致操作的时间复杂度上升。因此,在实际应用中,需要考虑树的平衡性,以保证其性能。

通过本博客,希望读者能够深入理解二叉搜索树的工作原理,并且能够运用这一数据结构解决实际问题。同时,也希望读者能够进一步探索二叉搜索树的相关内容,如平衡二叉搜索树(如AVL树和红黑树)以及其他高级数据结构,从而拓展自己的知识领域。

最后,二叉搜索树是计算机科学中的基础之一,深入了解它将有助于我们更好地理解和应用数据结构与算法,提高编程能力,并解决更复杂的计算问题。

在这里插入图片描述

  • 35
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 23
    评论
好的,我可以为您提供有关二叉搜索树的构建与应用的一些基本知识,并提供一个基于C语言的插入操作来创建二叉搜索树的示例代码。 二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树,它的每个节点最多有两个子节点,并且每个节点的左子节点的值小于该节点的值,右子节点的值大于该节点的值。通过这种方式,BST的节点可以被方便地插入、删除和查找。 BST常用于实现一些基于有序数据的算法,例如二分查找、范围查找等。在实际应用中,BST也常用于实现字典、集合等数据结构,或者作为其他数据结构的底层实现。 下面是一个基于C语言的插入操作的示例代码,用于创建一个二叉搜索树: ```c #include <stdio.h> #include <stdlib.h> typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; TreeNode *insert(TreeNode *root, int val) { if (root == NULL) { // 如果当前节点为空,则创建新节点并返回 TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode)); node->val = val; node->left = NULL; node->right = NULL; return node; } if (val < root->val) { // 如果插入值小于当前节点值,则插入到左子树中 root->left = insert(root->left, val); } else { // 如果插入值大于等于当前节点值,则插入到右子树中 root->right = insert(root->right, val); } return root; } void inorderTraversal(TreeNode *root) { // 中序遍历输出二叉搜索树 if (root != NULL) { inorderTraversal(root->left); printf("%d ", root->val); inorderTraversal(root->right); } } int main() { TreeNode *root = NULL; // 插入元素 root = insert(root, 5); insert(root, 3); insert(root, 7); insert(root, 2); insert(root, 4); insert(root, 6); insert(root, 8); // 中序遍历输出 inorderTraversal(root); return 0; } ``` 在这个示例代码中,我们定义了一个二叉树节点的结构体,并实现了一个名为`insert`的插入操作。在插入操作中,我们首先检查当前节点是否为空,如果为空则创建一个新节点并返回;如果不为空,则根据插入值与当前节点值的大小关系,递归地插入到左子树或右子树中。 最后,我们在`main`函数中调用`insert`操作插入了一些元素,并使用中序遍历遍历输出了整个二叉搜索树。 希望这个示例代码能够帮助您更好地理解二叉搜索树的构建与应用

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值