【C++】二叉搜索树

二叉搜索树

【概念】

二叉搜索树(BST,BinarySearchTree)又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

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

先定义二叉树的结构

struct BSTreeNode
{
	K _key;
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	BSTreeNode(const K& key)
		:_key(key)
		,_left(nullptr)
		,_right(nullptr)
	{}
};

 利用二叉树结构模拟实现二叉搜索树

template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
private:
	Node* _root = nullptr;
};

1. 二叉搜索树的插入

插入时要先判断_root是不是空节点

其次插入一个数(key)时要判断头结点与key的大小,大则往右树走,小则左树。再依次遍历判断。

最后判断要在父节点的哪个位置

	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 true;
			}
		}
		cur = new Node(key);
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else {
			parent->_left = cur;
		}
		return true;
	}

2. 搜索二叉树

本质上就是遍历 

	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 {
				return true;
			}
		}
		return false;
	}

 3. 中序遍历

中序遍历就是左子树,根,右子树。

采用递归思想。

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

当我们在main函数使用中序遍历时,发现传递不了root根节点。这时,我们把_InOrder设置为私有函数。在公有函数中引用私有函数_InOrder

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

4. 删除二叉树

 删除二叉树中的节点

如果删除叶子节点,直接删除

如果删除只有一个子节点的节点,则需要把他的父节点与他的子节点链接

如果删除有两个节点的节点,则需要找一个节点替代  左子树的最大 或 右子树最小

无子节点或者有一个子节点可以归为一类,我们只需把有一个子节点的节点或者没有节点的节点他们的孩子,交给节点的父节点来看管就行

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;
				return true;
}
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;
				return true;
}

删除两个子节点的节点

首先要找到右子树最小的节点与要删除的节点进行交换。(右子树最小节点的内容覆盖掉要删除的节点的内容,然后把右子树最小节点删除掉)

这里我们定义一个cur就是要删除的节点,和rightMin右子树最小的节点,和rightMinP右子树最小的节点的父节点。

 这里的大体思路就是找到rightMin并交换cur中的内容,rightMinP为rightMin的父节点,再让rightMinP指向rightMin的右孩子。

这里rightMinP有两种情况,如左图不是cur本身,还有右图是cur本身

					Node* rightMinP = cur;
					Node* rightMin = cur->_right;
					while (rightMin->_left)
					{
						rightMinP = rightMin;
						rightMin = rightMin->_left;
					}
					cur->_key = rightMin->_key;
					if (rightMinP->_left == rightMin)
						rightMinP->_left = rightMin->_right;
					else
						rightMinP->_right = rightMin->_right;
					delete rightMin;
					return true;

 删除二叉树总代码实现

bool Erase(int 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
		{
			// 删除
			//0-1个孩子的情况
			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;
				return true;
			}
			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;
				return true;
			}
			else {
				// 2 个孩子
				// 右子树的最大节点作为替代节点
				Node* rightMinP = cur;
				Node* rightMin = cur->_right;
				while (rightMin->_left)
				{
					rightMinP = rightMin;
					rightMin = rightMin->_left;
				}
				cur->_key = rightMin->_key;
				if (rightMinP->_left == rightMin)
					rightMinP->_left = rightMin->_right;
				else
					rightMinP->_right = rightMin->_right;
				delete rightMin;
				return true;
			}
		}
	}
	return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值