如何实现一棵二叉搜索树

1.二叉搜索树简介

什么是二叉搜索树?顾名思义,二叉搜索树是一颗二叉树,但是它却有搜索的功能,它是如何做到的呢?二叉搜索树的条件如下:

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

二叉搜索树如下图所示:

二叉搜索树其实还有一个隐藏功能:二叉搜索树走一个中序遍历,你会发现,遍历出来的数据是有序的。

二叉搜索树的查找效率非常高,最多只需要查找高度次

 2.二叉搜索树的实现

对于二叉搜索树的实现,无非就是实现二叉搜索树的增、删、查、改;但是如果在二叉搜索树中修改一个值,很有可能会破坏二叉搜索树的结构,导致这棵二叉搜索树不再是二叉搜索树。所以我们不能修改二叉搜索树中的值

2.1二叉搜索树节点的定义

二叉搜索树的结点中,我们需要定义左孩子和右孩子指针,分别指向左孩子和右孩子;当然还需要一个存储数据的_data;

    template<class K>
	struct BStreeNode
	{
		typedef BStreeNode<K> Node;
		Node* _left;
		Node* _right;
		K _data;

		BStreeNode(const K& val)
			:_left(nullptr)
			,_right(nullptr)
			,_data(val)
		{}
	};

2.2二叉搜索树的查找

二叉搜索树的查找功能,根据二叉搜索树的性质实现,需要查找的值,比当前结点大,就去右边查找,比当前结点小,就去左边查找;找到了就返回true,如果找到空了,说明没找到,返回false。

bool Find(const K& val)
{
	Node* temp = _root;
	while (temp)
	{
		if (val > temp->_data)
			temp = temp->_right;
		else if (val < temp->_data)
			temp = temp->_left;
		else
 			return true;
    }
			
    return false;
}

2.3二叉搜索树的插入

插入一个结点的时候,肯定要将该节点链接到它的父节点上去,所以查找插入位置的时候,需要记录其父节点,如果找到相等的说明不能插入了,返回false;如果找到空,说明找到插入位置了,但是不知道连接到父节点的那一边?通过判断 插入的值和父节点的值的大小决定链接到父节点的左边还是右边。 

        bool Insert(const K& val)
		{
			if (_root == nullptr)
			{
				_root = new Node(val);
				return true;
			}

			Node* temp = _root;
			Node* parent = nullptr;
			while (temp)
			{
				if (val > temp->_data)
				{
					parent = temp;
					temp = parent->_right;
				}
				else if (val < temp->_data)
				{
					parent = temp;
					temp = parent->_left;
				}
				else
				{
					return false;
				}
			}

			temp = new Node(val);
			if (val < parent->_data)
			{
				parent->_left = temp;
			}
			else if (val > parent->_data)
			{
				parent->_right = temp;
			}

			return true;
		}

2.4二叉搜索树的删除

二叉搜索树的删除其实就是删除节点,删除的结点可以划分为一下几种情况:

  • 该节点没有孩子
  • 该节点有一个孩子
  • 该节点有两个孩子

如下图所示:

如何实现二叉搜索树的删除呢?当删除的是叶子节点的时候,挺好的,直接删除即可,但是,如果删除的是有孩子的结点呢?这个时候就需要用到替换法删除。替换法删除就是找一个能替换当前结点的值,交换值,转换删除这个被替换的结点。

既然要替换,那我们用哪一个结点替换这个要删除的节点呢?选择的结点替换之后,不能改变当前二叉搜索树的结构,我们有以下两种选择:

  • 左子树的最大结点;左子树的最大结点其实就是左子树的最右边的结点,这个结点有个特点就是,右孩子为空,所以我们可以利用这个特性找这个结点。
  • 右子树的最小节点;右子树的最小结点其实就是右子树的最左边的结点,这个结点有个特点就是,左孩子为空,所以我们可以利用这个特性找这个结点。

代码实现如下:

        bool Erase(const K& val)
		{
			Node* parent = nullptr;
			Node* cur = _root;

			while (cur)
			{
				if (val > cur->_data)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (val < cur->_data)
				{
					parent = cur;
					cur = cur->_left;
				}
				else//相等 要删除了
				{
					if (cur->_left == nullptr)//左边为空
					{
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (cur == parent->_left)
							{
								//如果cur是根结点的话,没有parent
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right = cur->_right;
							}
						}
						
						delete cur;
						return true;
					}
					else if (cur->_right == nullptr) //右边为空
					{
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							//如果cur是根结点的话,没有parent
							if (cur == parent->_left)
								parent->_left = cur->_left;
							else
								parent->_right = cur->_left;
						}
						delete cur;
						return true;
					}
					else // 左右都不为空 替换法删除
					{
						Node* r_min_parent = cur;
						Node* r_min = cur->_right;

						while (r_min->_left) //当该循环停下来的时候说明找到了右边的最小结点
						{
							r_min_parent = r_min;
							r_min = r_min->_left;
						}
						cur->_data = r_min->_data;
						//交换完值之后,要删除的结点变成了r_min

						if (r_min == r_min_parent->_left) //当删除的是根结点的时候也适用
							r_min_parent->_left = r_min->_right;
						else
							r_min_parent->_right = r_min->_right;
						
						delete r_min;
						return true;
					}
				}
			}

			return false;
		}

3.二叉搜索树的应用

二叉搜索树是一种用来搜索的结构;搜索模型有两种,一种是Key搜索模型,一种是Key-Value搜索模型;

  • Key搜索模型主要用来 快速查找一个值在不在。如:门禁系统。
  • Key-Value搜索模型主要用来 通过一个值查找另一个值。如:字典查询。

4.性能分析

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

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

为了避免二叉搜索树退化成单支树,可以通过一些限制条件限制二叉搜索树的结构,比较有名的有AVL树红黑树。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值