搜索二叉树

单纯的二叉树,并不能体现出优秀的存储和查找能力,但是对二叉树附加一些规则,
就能让二叉树成为很高效的存储和查找的一种数据结构,所以今天会介绍,基于二
叉树和一些附加规则的树——搜索二叉树

1.搜索二叉树

搜索二叉树的规则也很简单,就是左节点要比根大,右节点比根大。

搜索二叉树_第1张图片

2. 搜索树的特点

1.中序遍历时得到的序列是有序序列
2.不支持有重复元素
3.查找效率是O(N),当树是满二叉树或者完全二叉树时,效率达到logN级别。
4.不支持修改,只有增删查

3. 搜索二叉树的实现

template<class K>
struct BSTreeNode
{
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;

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

template<class K>
class BSTree

{
	typedef BSTreeNode<K> Node;
public:
	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			parent = cur;
			if (cur->_key > key) cur = cur->_left;
			else if (cur->_key < key) cur = cur->_right;
			else return false;
		}
		if (parent->_key > key) parent->_left = new Node(key);
		else if (parent->_key < key) parent->_right = new Node(key);
		return true;
	}

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

	bool Erase(const K& key)
	{
		Node* parent = _root;
		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
			{
				Node* deNode = cur;
				if (deNode->_right == nullptr)
				{
					if (deNode->_key > parent->_key) parent->_right = deNode->_left;
					else if (deNode->_key < parent->_key) parent->_left = deNode->_left;
					else _root = cur->_left;
				}
				else if (deNode->_left == nullptr)
				{
					if (deNode->_key > parent->_key) parent->_right = deNode->_right;
					else if (deNode->_key < parent->_key) parent->_left = deNode->_right;
					else _root = cur->_right;
				}
				else
				{
					Node* subNode = deNode->_left;
					Node* par_subNode = deNode;
					while (subNode->_right) par_subNode = subNode, subNode = subNode->_right;
					swap(subNode->_key, deNode->_key);
					deNode = subNode;
					if (par_subNode->_left == deNode) par_subNode->_left = nullptr;
					if (par_subNode->_right == deNode) par_subNode->_right = nullptr;
				}

				delete deNode;
				return true;
			}
		}
		return false;
	}

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


private:


	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}


	Node* _root = nullptr;
};

搜索二叉树实现的细节

搜索二叉树的实现难点主要在删除。删除时我们需要考虑很多因素
比如删除叶子节点,只有左/右子树的节点,删除左右子树都在的节点。

a. 删除只有左/右子树的节点

删除叶子节点可以归类到这两个中的任意一个,不单独说了。
搜索二叉树_第2张图片
我们假如要删除26,采用的方法是将它右子树的根给它的父亲节点即可,同理删除之有左子树的时候,也仅需把左子树的根给父亲节点即可

需要注意的是,给父亲节点时需要判断被删的节点是他父亲节点的左还是右节点。

搜索二叉树_第3张图片

	删除节点是根的情况,第三个分支就是解决删除节点是根的情况,将左/右子树的根重新换成整棵树的根即可

b. 删除两子树都在的节点

采用的方法是替换法:将被删节点与它左子树的最大值或者右子树的最小值交换,
交换之后,只需要删除,交换后的叶子节点即可

左子树的最右边是左子树的最大值,右子树的最左边是右子树的最小值
左子树的最大值或者右子树的最小值必是叶子节点
交换之后,这棵树仍然是搜索二叉树
搜索二叉树_第4张图片

你可能感兴趣的:(数据结构,算法,c++)