C++——二叉搜索树的实现

1、二叉搜索树的概念

二叉搜索树又叫做二叉排序树,他或者是一棵空树,或者具有以下性质:

若他的左子树不为空,则左子树的所有节点的值都小于根节点的值,

若他的右子树不为空,则右子树的所有节点的值都大于根节点的值,

他的左右子树也分别为二叉搜索树;

2、二叉搜索树的操作

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

1.二叉搜索树的查找

从根节点开始找,比根大往右边查找,比根小往左边查找,最多查找高度次,走到空还没找到,则该值不存在;

2.二叉搜索树的插入

若树为空,则新增节点,赋值给root指针,

若树不为空,按二叉搜索树查找插入位置,插入新节点

 3.二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回,如果存在,则分为以下四种情况:

a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
其实a情况可以和b c 情况合并起来,这样我们只需要考虑三种删除方式:
情况b: 删除该节点,并使该节点的父亲节点指向删除节点的左节点
情况c:删除该节点,并使该节点的父亲节点指向删除节点的右节点
情况d:替换法,找到该节点右子树的最小节点或者左子树的最大节点,与该节点替换,然后删除右子树的最小节点或左子树的最大节点;

4.二叉搜索树的实现

#pragma once

#include<iostream>
#include<string>
using namespace std;
namespace key
{
	template<class K>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _key;
		BSTreeNode(const K& key)
			:_left(nullptr)
			,_right(nullptr)
			,_key(key)
		{ }

	};
	template<class K>
	class BSTree
	{
		typedef BSTreeNode<K> Node;
	public:
		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			cur = new Node(key);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}
			return true;
		}
		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if(cur->_key>key)
				{
					cur = cur->_left;
				}
				else
				{
					cout << "true" << endl;
					return true;
				}
			}
			cout << "false" << endl;
			return false;
		}
		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//删除
					//左为空,父亲指向我的右
					if (cur->_left == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right=cur->_right;
							}
						}
						delete cur;
					}
					//右为空,父亲指向我的左
					else if (cur->_right == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}
						delete cur;
					}
					else
					{
						//左右都不为空,替换法
						//查找右子树的最小节点或左子树的最大节点
						//我们这里找右子树的最小节点(也就是最左节点)
						Node* rightMinParent = cur;
						Node* rightMin = cur->_right;
						while (rightMin->_left)
						{
							rightMinParent = rightMin;
							rightMin = rightMin->_left;
						}
						swap(cur->_key, rightMin->_key);
						if (rightMinParent->_left == rightMin)
						{
							rightMinParent->_left = rightMin->_right;
						}
						else
						{
							rightMinParent->_right = rightMin->_right;
						}
						delete rightMin;
					}
					return true;
				}
			}
			return false;
		}
		void InOrder()
		{
			_InOrder(_root);
		    cout << endl;
		}

		
	private:

		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}


		Node* _root = nullptr;
	};
	void TestBSTree1()
	{
		BSTree<int> b;
		b.Insert(1);
		b.Insert(2);
		b.Insert(3);
		b.Insert(4);
		b.Insert(5);
		b.Find(6);
		b.Find(3);
		b.Find(5);
		b.InOrder();

	}
	void TestBSTree2()
	{
		int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
		BSTree<int> t1;
		for (auto e : a)
		{
			t1.Insert(e);
		}

		/*t1.InOrder();
		t1.Erase(8);
		t1.InOrder();*/


		for (auto e : a)
		{
			t1.Erase(e);
			t1.InOrder();
		}
	}
}

namespace key_value
{
	template<class K,class V>
	struct BSTreeNode
	{
		BSTreeNode<K,V>* _left;
		BSTreeNode<K,V>* _right;
		K _key;
		V _value;
		BSTreeNode(const K& key,const V& value)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _value(value)
		{ }

	};
	template<class K,class V>
	class BSTree
	{
		typedef BSTreeNode<K,V> Node;
	public:
		bool Insert(const K& key, const V& value)
		{
			if (_root == nullptr)
			{
				_root = new Node(key,value);
				return true;
			}
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			cur = new Node(key,value);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}
			return true;
		}
		Node* Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return cur;
				}
			}
			return cur;
		}
		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//删除
					//左为空,父亲指向我的右
					if (cur->_left == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right = cur->_right;
							}
						}
						delete cur;
					}
					//右为空,父亲指向我的左
					else if (cur->_right == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}
						delete cur;
					}
					else
					{
						//左右都不为空,替换法
						//查找右子树的最小节点或左子树的最大节点
						//我们这里找右子树的最小节点(也就是最左节点)
						Node* rightMinParent = cur;
						Node* rightMin = cur->_right;
						while (rightMin->_left)
						{
							rightMinParent = rightMin;
							rightMin = rightMin->_left;
						}
						swap(cur->_key, rightMin->_key);
						if (rightMinParent->_left == rightMin)
						{
							rightMinParent->_left = rightMin->_right;
						}
						else
						{
							rightMinParent->_right = rightMin->_right;
						}
						delete rightMin;
					}
					return true;
				}
			}
			return false;
		}
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}


	private:

		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << " ";
			_InOrder(root->_right);
		}


		Node* _root = nullptr;
	};

	void TestBSTree3()
	{
		BSTree<string, string> dict;
		dict.Insert("string", "字符串");
		dict.Insert("left", "左边");
		dict.Insert("insert", "插入");

		string str;
		while (cin >> str)
		{
			BSTreeNode<string, string>* ret = dict.Find(str);
			if (ret)
			{
				cout << ret->_value << endl;
			}
			else
			{
				cout << "无此单词,请重新输入" << endl;
			}
		}
	}

	void TestBSTree4()
	{
		// 统计次数
		string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
                         "苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };
		BSTree<string, int> countTree;
		for (const auto& str : arr)
		{
			auto ret = countTree.Find(str);
			if (ret == nullptr)
			{
				countTree.Insert(str, 1);
			}
			else
			{
				ret->_value++;
			}
		}

		countTree.InOrder();
	}

}

5、二叉搜索树的应用

1.K模型:K模型只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜索到的值;

比如:给一个单词word,判断该单词是否拼写正确,

2.K-V模型:每一个关键码都对应一个Value,即<Key,value>的键值对,

比如:英汉字典中用英文与中文的对应关系,通过英文可以快速找到对应的中文,

6、二叉搜索树的性能分析

对于有n个节点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是高度次,但对于同一个关键码集合,如果插入的次序不同,可能得到不同结构的二叉树:

 

最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:O(logN)
最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为O(N);

 

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ STL中没有直接提供二搜索实现,但STL中有一些关于的容器,比如set和map,它们底层的实现就是基于红黑(一种平衡二搜索)的。你可以使用这些容器来实现搜索的功能。关于二搜索的一些知识,比如二的遍历、迭代、线索二、堆、Huffman编码、AVL等都可以在STL中找到相应的实现。 二搜索的查找可以通过比较根节点的值和目标值的大小来判断是往左子还是往右子查找,并重复这个过程直到找到目标值或者遍历到叶子节点为止。常规实现使用循环来实现查找,递归实现使用递归函数来查找。 二搜索的插入操作也可以通过递归或循环来实现,根据目标值和当前节点的值的大小关系来决定是往左子还是往右子插入新节点。 STL中的二搜索容器如set和map提供了插入、删除和查找等功能,并且保持了二搜索的性质。你可以使用这些容器来处理二搜索相关的操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ STL 数据结构 ](https://download.csdn.net/download/xinxipan/3008948)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++ STL】-- 二搜索](https://blog.csdn.net/weixin_64609308/article/details/128018280)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值