二叉搜索树

目录

1.搜索二叉树的概念

2.二叉搜索树的操作

2.1 二叉搜索树的查找

2.2 二叉搜索树的插入 

2.3 二叉搜索树的删除 (比较复杂,了解即可)

三、二叉搜索树的实现

3.1 插入操作实现

3.2 查找操作实现

3.3 删除操作实现

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

1.搜索二叉树的概念

二叉搜索树又称二叉排序树,可以是一颗空树。

二叉搜索树具有一下的性质:

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

可以将一颗大的二叉搜索树理解为由很多小的搜索二叉树组成。

2.二叉搜索树的操作

2.1 二叉搜索树的查找

  1.  从根节点开始比较,查找,比根大的则在右子树去查找,比根小则去左边查找。
  2.  走到空的时候,如果还没有找到的话,则说明这个值不存在。

举个简单的例子.

2.2 二叉搜索树的插入 

 插入的过程是十分简单的,结合插入的原理,再结合图,就容易理解了。

2.3 二叉搜索树的删除 (比较复杂,了解即可)

具体分为以下3种情况,由简到繁。

1.要删除的结点没有孩子结点。

2.要删除的结点只有左孩子或右孩子

3.删除的结点具有左、右两个子结点(最繁琐的)

 理解起来是十分简单的,主要是实现过程比较繁琐。

三、二叉搜索树的实现

二叉树结点
template<class K,class V>
struct BSTNode
{
	BSTNode(const K& key, const V& value):_key(key),_value(value),_left(nullptr),_right(nullptr){}
	BSTNode<K,V>* _left;
	BSTNode<K,V>* _right;
	K _key;
	V _value;
};

class BSTree
{
	typedef struct BSTNode<K,V> Node; //这里一定得带上模板
private:
    Node* root =nullptr;
}

3.1 插入操作实现

bool _Insert(const K& key, const V& value)
	{
		if (root == nullptr)   如果根节点是空,则新的结点作为根节点
		{
			Node* newnode = new Node(key,value);
			root = newnode;
			return true;
		}

		Node* cur = root;             cur作为当前结点,并要定义cur的父结点,不然找到cur以后,无法进行链接
		Node* parent = nullptr;
		while (cur)                   根据二叉搜索树的特点,根节点左边的数值比根节点的数值小,右节点的数值比根节点的数值大。
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else                    如果相等,则说明已经存在,则无法插入。
				return false;
		}
        此时已经找到了需要插入的位置
		Node* newnode = new Node(key,value);
        判断此时的位置和parent的关系,  看cur此时的位置 是在parent的左边还是右边。
		if (key < parent->_key)
			parent->_right = newnode;
		else
			parent->_left = newnode;
		return true;
	}

3.2 查找操作实现

Node* _Find(const K& key)
	{                            
		if (root == nullptr)         与插入操作的逻辑一样,不过在这里不需要定义parent。
			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;
	}

3.3 删除操作实现

bool _Erase(const K& key)
	{
		if (root == nullptr)  如果根节点为空,则返回错误,很容易理解。
			return false;
		Node* cur = root;
		Node* parent = nullptr;
		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 = root->_right;
					}
					else                   到这一步说明它不是根节点,那么只需要将删除结点的子节点,接到其父节点即可
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
					cur = nullptr;
				}
				else if (cur->right == nullptr)  逻辑同 cur->left ==nullptr.
				{
					if (cur == root)
					{
						root = cur->_left;
					}
					else
					{
						if (cur == parent->_left)
							parent->_left = cur->_left;
						else
							parent->_right = cur->_left;
					}
					delete cur;
					cur = nullptr;
				}
				else             这里是说明  删除结点的左右子结点均不是空节点
				{
					Node* minNode = cur->_right; 需要在删除结点的右子树中去找到最小值。
					Node* minNodeP = cur;        并且需要记录其parent
					while (minNode->_left)       循环是为了找到最小值,最小值一定是在左子树。
					{
						minNodeP = minNode;
						minNode = minNode->_left;
					}
                    找到以后,将cur和最小值 进行交换。
					swap(cur->_key, minNode->_key);
					swap(cur->_value, minNode->_value);
                    再判断此时的最小值,是在其 parent的左边还是右边。
					if (minNode == minNodeP->_right)
					{
						minNodeP->_right = minNode->_right;
					}
					else
					{
						minNodeP->_left = minNode->_right;
					}
					delete minNode;
				}
				return true;
			}
		}
		return false;
	}

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

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

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二 叉搜索树的深度的函数,即结点越深,则比较次数越多。

最优情况,二叉搜索树为完全二叉树,其平均比较次数为 log2 N

最差情况,二叉搜索树退化为单支树,其平均比较次数为:N;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值