二叉搜索树

目录

概念

二叉搜索树结构 

二叉搜索树操作 

查找

插入

删除

 二叉搜索树性能分析


概念

二叉搜索树又称二叉排序树,它的中序遍历序列是一个有序序列。

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

通过二叉搜索树,我们可以初步了解map和set的特性。

二叉搜索树结构 

两种结构,一种是K结构,适用于set;另一种是KV结构,适用于map。

本篇讲解KV结构。

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:
		BSTree()
			:_root(nullptr)
		{

		}
    private:
        Node* _root;
}

 

二叉搜索树操作 

查找

要查找的key值大于当前节点值,那就到当前节点的右子树找;key值小于当前节点,就到当前节点的左子树找。

Node* Find(const K& key)
	{
		if (_root == nullptr)
		{
			return nullptr;
		}
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

递归法:先判断根节点是否是要寻找的,再根据值选择到左子树还是右子树寻找,如果走到空,证明没找到,直接返回空。 

Node* _Find_R(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return nullptr;
			}
			if (root->_key == key)
			{
				return root;
			}
			if (root->_key < key)
			{
				return _Find_R(root->_right, key);
			}
			else
			{
				return _Find_R(root->_left, key);
			}
		}
Node* Find_R(const K& key)
		{
			return _Find_R(_root, key);
		}

 

插入

插入的前提要先寻找一个空节点,然后根据它与父亲值的大小决定在左还是右插入。

所以我们要寻找空节点时要保存父亲节点。

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;
		}
bool _Insert_R(Node*& root, const K& key,const V&value)
		{
			if (root == nullptr)
			{
				root = new Node(key,value);
				return true;
			}
			if (root->_key < key)
			{
				return _Insert_R(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _Insert_R(root->_left, key);
			}
			else
			{
				return false;
			}
		}
bool Insert_R(const K& key,const V&value)
		{
			return _Insert_R(_root, key);
		}

 

删除

删除有有三种情况:

  • 要删除节点的左子树为空,让父亲链接它的右子树
  • 要删除节点的右子树为空,让父亲链接它的左子树
  • 左右子树都不为空,采用替代法删除,在右子树寻找最左节点或左子树寻找最右节点。
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 (parent == nullptr)
						{
							_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 (parent == nullptr)
						{
							_root = cur->_left;
						}
						else if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
						delete cur;

					}
					//删除节点左右都不为空
					//替换法删除
					else
					{
						Node* minparent = cur;
						Node* min = cur->_right;
						while (min->_left)
						{
							minparent = min;
							min = min->_left;
						}
						swap(cur->_key, min->_key);
						swap(cur->_value, min->_value);
						if (minparent->_right == min)
						{
							minparent->_right = min->_right;
						}
						else
						{
							minparent->_left = min->_right;
						}
						delete min;
					}
					return true;
				}
			}
            //未找到节点
			return false;
		}
bool _Erase_R(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (root->_key > key)
			{
				return _Erase_R(root->_left, key);
			}
			else if (root->_key < key)
			{
				return _Erase_R(root->_right, key);
			}
			else
			{
				Node* del = root;
				if (root->_left == nullptr)
				{
					root = root->_right;
				}
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				else
				{
					Node* min = root->_right;
					while (min&&min->_left)
					{
						min = min->_left;
					}
					swap(root->_key, min->_key);
					swap(root->_value, min->_value);
					return _Erase_R(root->_right, key);
				}
				delete del;
				return true;
			}
		}

 二叉搜索树性能分析

最好情况下:满二叉树,查找效率为logn

最坏情况下:单枝树,查找效率为n

所以二叉搜索树还是有缺陷的,如何解决缺陷?这就要讲到二叉平衡搜索树,后面章节进行讲解。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嚞譶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值