【数据结构】 模拟实现搜索二叉树

引言:随着数据结构STL学习的不断深入,我们已经了解了序列式容器vector,list,string等,接下来进入到关联式容器中。两者都被用来存储数据,与序列式容器的线性结构不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。根据应用场景的不同,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。那么今天我们先来简单实现一下搜索二叉树吧。

二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值 它的左右子树也分别为二叉搜索树

如图所示
在这里插入图片描述

  • :在整个实现过程中笔者发现,增添,查找,修改节点都是遍历整个树,直到找到key值返回true,都相对较为简单,比较令人头疼的就是删除操作,因为整个中序遍历后必须为有序,所以不能破坏整个树的大致结构,要让他时刻保持中序有序。

删除过程分以下三种情况:
1.左为空
2.有为空
3.左右都不为空

代码实现如下
BinarySearch.h

#include<iostream>
using namespace std;

template<class k>

struct BSTreeNode
{
	BSTreeNode<k>* _left;
	BSTreeNode<k>* _right;
	k _key;

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

template<class k>
class BSTree
{ 
	typedef BSTreeNode<k> Node;
public:
	BSTree()
		:_root(nullptr)
	{}

	~BSTree()
	{
        delete _root;
        _root=nullptr;
	}

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

	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//走到这表示找到了
			{
				//分为三种情况
				//1.左为空
				//2.右为空
				//3.左右都不为空
				Node* del = cur;
				if (cur->_left == nullptr)
				{
					if (parent == nullptr)
					{
						_root=cur->_right;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
				}
				else if (cur->_right == nullptr)
				{
					if (parent->_left == cur)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}
				}
				else
				{
			
					Node* lessparent = cur;
					Node* rightLess = cur->_right;
					while (rightLess->_left)
					{
						lessparent = rightLess;
						rightLess = rightLess->_left;
					}
					cur->_key = rightLess->_key;
					del = rightLess;
					if (lessparent->_left == rightLess)
					{
						lessparent->_left = rightLess->_right;
					}
					else
					{
						lessparent->_right = rightLess->_right;
					}
				}
				delete del;
				return true;
			}
		}
		return false;
	}

	void inOrder()
	{
		_inOrder(_root);
		cout << endl;
	}

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

	//递归版本实现
	bool InsertR(const k& key)
	{
		return _Insert(_root, key);
	}

	bool _Insert(Node* & root, const k& key)
	{
		if (root == nullptr)
			root = new Node(key);

		if (root->_key < key)
		{
			return _Insert(root = root->_right,key);
		}
		else if (root->_key>key)
		{
			return _Insert(root = root->_left, key);
		}
		else
		{
			return false;
		}
	}

	Node* FindR(const k& key)
	{
		return _FindR(root->_key, key);
	}

	Node* _FindR(Node* root, const k& key)
	{
		if (root == nullptr)
			return nullptr;

		if (root->_key == key)
		{
			return root;
		}
		else if (root->_key < key)
		{
			return _FindR(root->_right, key);
		}
		else
		{
			return _FindR(root->_left, key);
		}
	}

	bool EraseR( const k& key)
	{
		//Node* root=_root;
		return _EraseR(root->_key, key);
	}

	bool _EraseR(Node* root, const k& key)
	{
		if (root == nullptr)
			return false;

		Node* cur = root;
		Node* parent = cur;
		

		if (cur->_key < key)
		{
			parent = cur;
			return _EraseR(cur->_right,key);
		}
		else if (cur->_key>key)
		{
			parent = cur;
			return _EraseR(cur->_left, key);
		}
		else
		{
			//分为三种情况
			//1、左为空
			//2、右为空
			//3.左右都不为空
             Node* del=cur;
			 if (cur->_left == nullptr)
			{
				 if (parent == nullptr)
				 {
					 root = cur->_right;
				 }
				 else
				 {
					 if (parent->_left == cur)
					 {
						 parent->_left = cur->_right;
					 }
					 else
					 {
						 parent->_right = cur->_right;
					 }
				 }
			}
			 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;
					 }
				 }
			 }
			 else
			 {
				 Node* Lessparent = nullptr;
				 Node* Lessright = cur->_right;
				 while (Lessright->_left)
				 {
					 Lessparent = Lessright;
					 Lessright = Lessright->_left;
				 }
				 cur->_key = Lessright->_key;
				 del = Lessright;
				 if (Lessparent->_left == Lessright)
				 {
					 Lessparent->_left = Lessright->_right;
				 }
				 else
				 {
					 Lessparent->_right = Lessright->_right;
				 }
			 }
			 delete del;
			 return true;
		}
	}
private:
	Node* _root;
};

void TestBSTree()
{
	int a[] = {5,3,4,1,7,8,2,6,0,9 };
	BSTree<int> t;
	for (auto e : a)
	{
		t.Insert(e);
	}

	t.inOrder();
	t.EraseR(2);
	t.EraseR(8);
	t.EraseR(1);
	t.EraseR(7);
	t.EraseR(5);
	t.inOrder();
}

Test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"BSTree.h"
int main()
{
	TestBSTree();
	system("pause");
	return 0;
}

在这里插入图片描述

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

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log2^N
在这里插入图片描述
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:2/N
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐