C++ 二叉搜索树的实现

二叉树搜索树

二叉搜索树,同时也称为二叉排序树。它可以为一个空树,或者满足二叉搜索树的性质

  • 如果左子树不为空时,左子树的值小于双亲结点
  • 如果右子树不为空时,右子树的值大于双亲结点
  • 同时,它的左右子树也满足二叉搜索树的性质
    二叉搜索树
    当对二叉搜索树进行中序遍历时,会得到有序序列,所以又被称为二叉排序树
    例如对上图的树进行中序遍历时会产生:【0 1 2 3 4 5 6 7 8 9】
二叉搜索树的操作
  • 树的结构
    按照模板将树的结构给出
template<class T>
struct BSNode
{
	BSNode(const T&_data = T()) //构造函数,如果用户没有给参数,则调用默认参数
		:left(nullptr)
		,right(nullptr)
		,data(_data)
	{

	}
	BSNode<T>* left;
	BSNode<T>* right;
	T data;
};
  • 查找

根据二叉搜索树的性质,左子树的值比根结点的值小,右子树的值比根结点的值大,进行查找。
在这里插入图片描述

Node* Find(const T& _data)
	{
		Node* cur = root;
		while (cur)
		{
			if (cur->data < _data)
				cur = cur->right;
			else if (cur->data > _data)
				cur = cur->left;
			else if (cur->data == _data)
				return cur;
		}
		return nullptr;
	}
  • 插入 bool Insert(const T&_data)
    在这里插入图片描述
    i.先判断二叉搜索树是不是空树,如果是空树直接插入
if(root == nullptr)
{
	root = BSNode(_data);
	return true;
}

ii.如果树不为空,则判断要把数值插入的位置

Node *cur = root;   //从根结点开始找要插入的位置
Node *parent = nullptr; // 用来保存要插入位置的双亲结点
while(cur)
{
	parent = cur;    //将双亲结点指向cur
	if (cur->data < _data)  // 用cur 开始往下查找
		cur = cur->right;
	else if (cur->data > _data)
		cur = cur->left;
	else
		return false;
}

iii.找到结点,插入操作

cur = new Node(_data);
if (_data < parent->data)  // 用双亲结点来判断,要插入的结点,应给插入到双亲的哪边
	parent->left = cur;
else
	parent->right = cur;
return true;
代码:
bool Insert(const T&_data) //将一个元素插入
	{
		if (root == nullptr)
		{
			root = new Node(_data);
			return true;
		}
		Node* cur = root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->data < _data)
				cur = cur->right;
			else if (cur->data > _data)
				cur = cur->left;
			else
				return false;
		}
		cur = new Node(_data);
		if (_data < parent->data)
			parent->left = cur;
		else
			parent->right = cur;
		return true;
	}
  • 删除 bool Delete(const T& _data)

i.先判断删除的数值在二叉树中,如果不存在,则返回, 否则要删除的结点可能分下面三种情况
a. 待删除结点只有左孩子
b.待删除结点只有右孩子
c.待删除结点左右孩子都存在
在这里插入图片描述
在a类情况和b类情况中需要加一个特判(待删除结点为根结点)

bool Delete(const T& _data)
	{
		if (root == nullptr) //结点为空
		{
			return false;
		}
		Node* cur = root;
		Node* parent = nullptr;
		while (cur)
		{
			if (_data == cur->data)
				break;
			else if (cur->data < _data)
			{
				parent = cur;
				cur = cur->right;
			}
			else
			{
				parent = cur;
				cur = cur->left;
			}
		}
		if (cur == nullptr) //未找到
			return false;

		//1、只有左孩子
		if (cur->right == nullptr)
		{
			if (cur == root)
				root = cur->left;
			else
			{
				if (cur == parent->left)
				{
					parent->left = cur->left;
				}
				else
				{
					parent->right = cur->left;
				}
			}
		}
		//只有右子树
		else if(cur->left == nullptr)
		{
			if (cur == root)
				root = cur->right;
			else
			{
				if (cur == parent->left)
				{
					parent->left = cur->right;
				}
				else
				{
					parent->right = cur->right;
				}
			}
		}
		//左右子树都存在	
		/*找一个替换的结点:在左子树找最大值,或者在右子树中找最大值,进行替换
		*/
		else 
		{
			if (cur->left != nullptr || cur->right != nullptr)
			{
				//在右子树中找最小值进行替换
				Node *replace = cur->right;
				parent = cur;
				while (replace->left)//在右子树中最左边的结点值最小
				{
					parent = replace;
					replace = replace->left;
				}
				cur->data = replace->data; //将要删除的结点与右子树中最小结点的值进行替换
				if (replace == parent->left)
				{
					parent->left = replace->right;
				}
				else
				{
					parent->right = replace->right;
				}
				delete replace;
				replace = nullptr;
			}
			return true;
		}
		return false;
	}

完整代码

template<class T>
struct BSNode
{
	BSNode(const T&_data = T())
		:left(nullptr)
		,right(nullptr)
		,data(_data)
	{

	}
	BSNode<T>* left;
	BSNode<T>* right;
	T data;
};
template<class T>
class BSTree
{
	typedef BSNode<T> Node;
public:
	BSTree()
		:root(nullptr)
	{
	}
	~BSTree()
	{
		Destory(root);
	}
	BSTree(const BSTree<T>& t)
	{
		root = copy(t);
	}
	Node *copy(BSTree* t)
	{
		if (t.root == nullptr)
			return nullptr;
		Node *temp = new Node;
		temp->data = t->root;
		temp->left = copy(t->left);
		temp->right = copy(t->right);
		return temp;
	}
	bool Insert(const T&_data) //将一个元素插入
	{
		if (root == nullptr)
		{
			root = new Node(_data);
			return true;
		}
		Node* cur = root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->data < _data)
				cur = cur->right;
			else if (cur->data > _data)
				cur = cur->left;
			else
				return false;
		}
		cur = new Node(_data);
		if (_data < parent->data)
			parent->left = cur;
		else
			parent->right = cur;
		return true;
	}

	Node* Find(const T& _data)
	{
		Node* cur = root;
		while (cur)
		{
			if (cur->data < _data)
				cur = cur->right;
			else if (cur->data > _data)
				cur = cur->left;
			else if (cur->data == _data)
				return cur;
		}
		return nullptr;
	}

	bool Delete(const T& _data)
	{
		if (root == nullptr) //结点为空
		{
			return false;
		}
		Node* cur = root;
		Node* parent = nullptr;
		while (cur)
		{
			if (_data == cur->data)
				break;
			else if (cur->data < _data)
			{
				parent = cur;
				cur = cur->right;
			}
			else
			{
				parent = cur;
				cur = cur->left;
			}
		}
		if (cur == nullptr) //未找到
			return false;

		//1、只有左孩子
		if (cur->right == nullptr)
		{
			if (cur == root)
				root = cur->left;
			else
			{
				if (cur == parent->left)
				{
					parent->left = cur->left;
				}
				else
				{
					parent->right = cur->left;
				}
			}
		}
		//只有右子树
		else if(cur->left == nullptr)
		{
			if (cur == root)
				root = cur->right;
			else
			{
				if (cur == parent->left)
				{
					parent->left = cur->right;
				}
				else
				{
					parent->right = cur->right;
				}
			}
		}
		//左右子树都存在	
		/*找一个替换的结点:在左子树找最大值,或者在右子树中找最小值,进行替换
		*/
		else 
		{
			if (cur->left != nullptr || cur->right != nullptr)
			{
				//在右子树中找最小值进行替换
				Node *replace = cur->right;
				parent = cur;
				while (replace->left)//在右子树中最左边的结点值最小
				{
					parent = replace;
					replace = replace->left;
				}
				cur->data = replace->data; //将要删除的结点与右子树中最小结点的值进行替换
				if (replace == parent->left)
				{
					parent->left = replace->right;
				}
				else
				{
					parent->right = replace->right;
				}
				delete replace;
				replace = nullptr;
			}
			return true;
		}
		return false;
	}

private:
	void Destory(Node*& root)
	{
		if (root)
		{
			Destory(root->left);
			Destory(root->right);
			root = nullptr;
		}
	}
	Node *root;
};

性能分析:
每次插入或删除结点时都必须进行查找,所以查找的效率决定删除或者插入的效率,最坏情况下,当二叉搜索树为一个单支,其搜索的时间复杂度为O(n)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值