【C++的剃刀】我不允许你还不会二叉搜索树BST


db43723fcefb47a09b575a7812877e29.png


 学习编程就得循环渐进,扎实基础,勿在浮沙筑高台  

 循环渐进Forward-CSDN博客


Hello,这里是kiki,今天继续更新C++部分,我们继续来扩充我们的知识面,我希望能努力把抽象繁多的知识讲的生动又通俗易懂,今天要讲的是二叉树进阶-二叉搜索树~


目录

 循环渐进Forward-CSDN博客

二叉搜索树概念

二叉搜索树操作  

二叉搜索树的查找

二叉搜索树的插入

二叉搜索树的删除

二叉搜索树的应用

二叉搜索树的性能分析


二叉搜索树概念

二叉搜索树又称二叉排序树,它有可能是一棵空树,有可能是具有以下性质的二叉树:
1、若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2、若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3、它的左右子树也分别为二叉搜索树

二叉搜索树操作  

当一颗二叉搜索树具有以下结点时,其形态是这样的:

int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};

7a51dee029dc48d79f841c4b3f279470.png

二叉搜索树的查找

a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

b、最多查找高度次,走到到空,还没找到,这个值不存在。 

/*查找元素key*/
bool find(Node* root, int key)
{
	while (root != NULL)
	{
		if (key == root->data)
			return true;
		else if (key < root->data)
			root = root->left;
		else
			root = root->right;
	}
	return false;
}

二叉搜索树的插入

插入的具体过程如下:

a. 树为空,则直接新增节点,赋值给root指针

b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

void insert(int key)
{
	//定义一个临时指针 用于移动
	Node* temp = root;//方便移动 以及 跳出循环
	Node* prev = NULL;//定位到待插入位置的前一个结点
	while (temp != NULL)
	{
		prev = temp;
		if (key < temp->data)
		{
			temp = temp->left;
		}
		else if(key > temp->data)
		{
			temp = temp->right;
		}
		else
		{
			return;
		}
	}
 
	if (key < prev->data)
	{
		prev->left = (Node*)malloc(sizeof(Node));
		prev->left->data = key;
		prev->left->left = NULL;
		prev->left->right = NULL;
	}
	else
	{
		prev->right = (Node*)malloc(sizeof(Node));
		prev->right->data = key;
		prev->right->left = NULL;
		prev->right->right = NULL;
	}
}

二叉搜索树的删除

 首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

 a. 要删除的结点无孩子结点  

b. 要删除的结点只有左孩子结点  

c. 要删除的结点只有右孩子结点  

d. 要删除的结点有左、右孩子结点

int delete_node(Node* node, int key)
{
	if (node == NULL)
	{
		return -1;
	}
	else
	{
		if (node->data == key)
		{
			//当我执行删除操作 需要先定位到删除结点的前一个结点(父节点)
			Node* tempNode = prev_node(root, node, key);
			Node* temp = NULL;
			
			//如果右子树为空,只需要重新连接结点(包含叶子结点),直接删除
			if (node->right == NULL)
			{
				temp = node;
				node = node->left;
				/*判断待删除结点是前一个结点的左边还是右边*/
				if (tempNode->left->data == temp->data)
				{
					Node* free_node = temp;
					tempNode->left = node;
					free(free_node);
					free_node = NULL;
				}
				else
				{
					Node* free_node = temp;
					tempNode->right = node;
					free(free_node);
					free_node = NULL;
				}
			}
			else if (node->left == NULL)
			{
				temp = node;
				node = node->right;
				if (tempNode->left->data == temp->data)
				{
					Node* free_node = temp;
					tempNode->left = node;
					free(free_node);
					free_node = NULL;
				}
				else
				{
					Node* free_node = temp;/
					tempNode->right = node;
					free(free_node);
					free_node = NULL;
				}
			}
			else//左右子树都不为空
			{
				temp = node;
				/*往左子树 找最大值*/
				Node* left_max = node;//找最大值的临时指针
				left_max = left_max->left;//先到左孩子结点
				while (left_max->right != NULL) 
				{
					temp = left_max;
					left_max = left_max->right;
				}
				node->data = left_max->data;
				if (temp != node)
				{
					temp->right = left_max->left;
					free(left_max);
					left_max = NULL;
				}
				else
				{
					temp->left = left_max->left;
					free(left_max);
					left_max = NULL;
				}
			}
			
		}
		else if(key < node->data)
		{
			delete_node(node->left, key);
		}
		else if (key > node->data)
		{
			delete_node(node->right, key);
		}
	}
}

二叉搜索树的应用

1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到 的值。 比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

2. KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方 式在现实生活中非常常见:

比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英 文单词与其对应的中文<word, chinese>就构成一种键值对。

再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出 现次数就是<word, count>就构成一种键值对。

#pragma once

// 改造二叉搜索树为KV结构
template<class K, class V>
struct BSTNode
{
	BSTNode(const K& key = K(), const V& value = V())
		: _pLeft(nullptr), _pRight(nullptr), _key(key), _Value(value)
	{}
	BSTNode<T>* _pLeft;
	BSTNode<T>* _pRight;
	K _key;
	V _value
};
template<class K, class V>
class BSTree
{
	typedef BSTNode<K, V> Node;
	typedef Node* PNode;
public:
	BSTree() : _pRoot(nullptr) {}
	PNode Find(const K& key);
	bool Insert(const K& key, const V& value)
		bool Erase(const K& key)
private:
	PNode _pRoot;
};
void TestBSTree3()
{
	// 输入单词,查找单词对应的中文翻译
	BSTree<string, string> dict;
	dict.Insert("string", "字符串");
	dict.Insert("tree", "树");
	dict.Insert("left", "左边、剩余");
	dict.Insert("right", "右边");
	dict.Insert("sort", "排序");
	// 插入词库中所有单词
	string str;
	while (cin >> str)
	{
		BSTreeNode<string, string>* ret = dict.Find(str);
		if (ret == nullptr)
		{
			cout << "单词拼写错误,词库中没有这个单词:" << str << endl;
		}
		else
		{
			cout << str << "中文翻译:" << ret->_value << endl;
		}
	}
}
void TestBSTree4()
{
	// 统计水果出现的次数
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
   "苹果", "香蕉", "苹果", "香蕉" };
	BSTree<string, int> countTree;
	for (const auto& str : arr)
	{
		// 先查找水果在不在搜索树中
		// 1、不在,说明水果第一次出现,则插入<水果, 1>
		// 2、在,则查找到的节点中水果对应的次数++
		//BSTreeNode<string, int>* ret = countTree.Find(str);
		auto ret = countTree.Find(str);
		if (ret == NULL)
		{
			countTree.Insert(str, 1);
		}
		else
		{
			ret->_value++;
		}
	}
	countTree.InOrder();
}

二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二 叉搜索树的深度的函数,即结点越深,则比较次数越多。 但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

5878cbb1d0cb49bd8b98c37bd793abfb.png

最优情况下,二叉搜索树为完全二叉树 ( 或者接近完全二叉树 ),其平均比较次数为:eq?%24log_2%20N%24
最差情况下,二叉搜索树退化为单支树 ( 或者类似单支 ) ,其平均比较次数为: eq?%24%5Cfrac%7BN%7D%7B2%7D%24

学习编程就得循环渐进,扎实基础,勿在浮沙筑高台  


相关推荐

  1. 判断是搜索c++】

    2024-07-23 09:44:02       36 阅读
  2. C++BST搜索)应用场景

    2024-07-23 09:44:02       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-23 09:44:02       101 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-23 09:44:02       109 阅读
  3. 在Django里面运行非项目文件

    2024-07-23 09:44:02       87 阅读
  4. Python语言-面向对象

    2024-07-23 09:44:02       96 阅读

热门阅读

  1. 后端开发面试题6(附答案)

    2024-07-23 09:44:02       22 阅读
  2. 紫龙游戏服务器面试

    2024-07-23 09:44:02       21 阅读
  3. C#类型基础Part2-对象判等

    2024-07-23 09:44:02       23 阅读
  4. 量化机器人能否提高市场预测精度?

    2024-07-23 09:44:02       26 阅读
  5. ELK Stack入门之部署EFK架构

    2024-07-23 09:44:02       22 阅读
  6. uniapp刷新当前页面bug

    2024-07-23 09:44:02       24 阅读
  7. ArcGIS Pro SDK (九)几何 12 多面体

    2024-07-23 09:44:02       22 阅读
  8. 数据库连接池

    2024-07-23 09:44:02       24 阅读
  9. RKNN执行bash ./build-linux_RK3566_RK3568.sh 报错

    2024-07-23 09:44:02       24 阅读
  10. 数学建模--图论与最短路径

    2024-07-23 09:44:02       23 阅读
  11. mariadb安装在服务器(Linux)

    2024-07-23 09:44:02       24 阅读