C++ 二叉搜索树

1. 概念

二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树,它具有以下特点:

  1. 每个节点最多有两个子节点,分别称为左子节点和右子节点。
  2. 对于每个节点,其左子树中的所有节点的值都小于该节点的值,而其右子树中的所有节点的值都大于该节点的值。
  3. 二叉搜索树中不存在重复的节点。
  4. 二叉搜索树又称排序二叉树,因为根据上述特点,中序遍历这棵树就得到升序序列。

2. 操作

2.1 查找

先从根开始比较,如果查找的值大于根,根据该树特点,那么要查找的值肯定在右子树,然后再查找右子树,否则相反。
根据上述思想,我们只需要查找高度次就能查到,否则查不到,时间复杂度为O(log n)。

2.2 插入

如果树为空,直接插入。
先从根开始比较,如果要插入的值大于根,就插入右子树,继续比较,直到为空,然后插入该值。

2.3 删除

删除比较麻烦,我们先查找要删除的值是不是在树里,如果在树里面,要分四种情况讨论。

  1. 删除的值为叶子节点。直接删除就行。
  2. 删除的值有左孩子。将左孩子连接到要删除节点的父亲节点。
  3. 删除的值有右孩子。将右孩子连接到要删除节点的父亲节点。
  4. 删除的值有两个孩子。在它的左子树里面找到最大节点,或右子树里面找到最小节点,替换掉要删除的值。然后删除左子树的最大节点或右子树最小节点,因为这种节点是满足上述三种情况的节点,按照其方法删掉就行。

3. 模拟实现

template<class K, class V>
	struct BSTreeNode
	{
		typedef struct BSTreeNode<K, V> Node;
		Node* _left;
		Node* _right;

		K _key;
		V _val;

		BSTreeNode(const K& key,const V& val)
			:_left(nullptr)
			,_right(nullptr)
			,_key(key)
			,_val(val)
		{}
	};
	template<class K, class V>
	class BSTree
	{
		typedef struct BSTreeNode<K, V> Node;
	public:
		bool Insert(const K& key, const V& value)
		{
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (key < cur->_key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (key > cur->_key)
				{
					parent = cur;
					cur = cur->_right;
				}	
				else
					return false;
			}
			cur = new Node(key, value);
			if (!parent)
				_root = cur;
			else if (cur->_key > parent->_key)
				parent->_right = cur;
			else if (cur->_key < parent->_key)
				parent->_left = cur;

			return true;
		}
		Node* Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key > key)
					cur = cur->_left;
				else if (cur->_key < key)
					cur = cur->_right;
				else
					return cur;
			}
			cout << "找不到" << endl;
			return nullptr;
		}
		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
					break;
			}
			if (!cur)
				return false;
			//没孩子/一个孩子
			if (!cur->_left)
			{
				Node* tmp = cur;
				if (cur == _root)
				{
					_root = cur->_right;
				}
				else
				{
					cur = cur->_right;
					if (cur->_key > parent->_key)
						parent->_right = cur;
					else if (cur->_key < parent->_key)
						parent->_left = cur;
				}
				delete tmp;
				return true;
			}
			else if (!cur->_right)
			{
				Node* tmp = cur;
				if (cur == _root)
				{
					_root = cur->_left;
				}
				else
				{
					cur = cur->_left;
					if (cur->_key > parent->_key)
						parent->_right = cur;
					else if (cur->_key < parent->_key)
						parent->_left = cur;
				}
				delete tmp;
				return true;
			}
			else  //两个孩子,替换法,找左边最大,或右边最小替换
			{
				Node* parent = cur;
				Node* rightMinParent = cur;
				Node* rightMin = cur->_right;
				while (rightMin->_left)
				{
					rightMinParent = rightMin;
					rightMin = rightMin->_left;
				}
				parent->_key = rightMin->_key;
				parent->_val = rightMin->_val;
				if (rightMin == rightMinParent->_left)
					rightMinParent->_left = rightMin->_right;
				else
					rightMinParent->_right = rightMin->_right;
				delete rightMin;
				return true;
			}
			return false;
		}
		void _InOrder(Node* root)
		{
			if (!root)
				return;
			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}
		void InOrder()
		{
			_InOrder(_root);
			return;
		}
	private:
		Node* _root = nullptr;
	};

4. 应用

  1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
    比如:小区的汽车栏杆,只将你车的车牌为关键码,在树里面查找,如果你是该小区的就自动抬杆,否则就进不去。
  2. KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。
    比如:
    1. 汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对。
    2. 统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。
    3. 商场的汽车栏杆,你进入,系统就将你的<车牌号码,入库时间>作为键值对插入到树里,出去的时候就查找,然后按时间收费。

5. 性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
如果对于同一个关键值的集合,插入的顺序不同,那查找的效率就不同,如果插入完之后,形状和满二叉树一样,那查找效率最高为O(log n),但如果插入完之后,形状是竖直的,那么查找效率就退化到O(n),那么这种结构就没有用了。AVL树和红黑树就是解决这种情况的。

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值