二叉搜索树(基础)

本文介绍了二叉搜索树的基本概念,包括其特性及在内存查找中的高效性。详细阐述了如何使用C++模板实现二叉搜索树的插入、查找和删除操作,并提供了相应的递归辅助函数。通过示例代码展示了如何进行中序遍历,以展示搜索二叉树的有序性质。此外,还讨论了删除操作中的不同情况处理,如无子节点、单子节点和双子节点的情况。
摘要由CSDN通过智能技术生成

二叉搜索树(BinarySearchTree)

所有左子树的值都小于根,所有右子树的值都大于根
用处:在内存中查找
最多查找高度次
如果能做到满二叉树或完全二叉树,在中国14亿人中找到心动的人只需要31次,10亿是30次(2的三十次方)

查找的话:需要后期的平衡二叉树,和AVL树

搜索二叉树中序遍历时一定程度上是有序的,所以又被叫做排序二叉树

比较数据的大小,我们在声明模板的时候一般申请成key - --class K
Insert操作
先序遍历可以排序+去重
查找Find也很简单

删除操作

#pragma once
#include<iostream>
#include<cstdio>

using namespace std;

//二叉树以后,模板参数用K(key)
template<class K>
struct BSTreeNode
{
	BSTreeNode<K>* left;
	BSTreeNode<K>* right;
	K _val;

	BSTreeNode(const K& val)
		:left(nullptr)
		,right(nullptr)
		,_val(val)
	{}
};

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

	bool Insert(const K& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		
		while (cur)
		{
			if (cur->_val < val)
			{
				parent = cur;
				cur = cur->right;
			}
			else if (cur->_val > val)
			{
				parent = cur;
				cur = cur->left;
			}
			else
			{
				return false;//树中不允许有相同的元素存在
			}
		}

		//已经找到了位置,开始放结点
		//想要链接的话,必须要通过parent
		//单靠自己所在位置是链接不了的
		cur = new Node(val);
		if (parent->_val < val)
		{
			parent->right = cur;
		}
		else
		{
			parent->left = cur;
		}
		return true;
	}

	bool Find(const K& val)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_val < val)
			{
				cur = cur->right;
			}
			else if (cur->_val > val)
			{
				cur = cur->left;
			}
			else
			{
				return true;
			}
		}
		return false;
	}

	bool Erase(const K& val)
	{
		Node* parent = nullptr;
		Node* cur = _root;
		//开始找需要删除的元素
		while (cur)
		{
			if (cur->_val < val)
			{
				parent = cur;
				cur = cur->right;
			}
			else if (cur->_val > val)
			{
				parent = cur;
				cur = cur->left;
			}
			else
			{
				//找到了以后分三种情况
				//1 .该结点没有孩子 2 .该节点没有孩子 3.该节点有两个孩子
				//前两种情况可以直接删除,最后一种情况可以用替换法删除
				//将左子树的最右结点(也就是最大结点)或者右子树的最小节点(最左)交换删除
				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;
				}
				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;
				}
				else
				{
					//该结点既有左孩子又有右孩子,那么我们找左树的最大或者右树的最小
					//在这里我们找右树的最小(也就是最左子树)
					Node* minParent = cur;
					Node* min = cur->right;
					//找小
					while (min->left)
					{
						minParent = min;
						min = min->left;
					}
					
					cur->_val = min->_val;
					
					if (minParent->left == min)
					{
						minParent->left = min->right;
					}
					else
					{
						minParent->right = cur->right;
					}
					delete min;
				}
				return true;
			}
			
		}
		//没有找到
		return false;
	}

	//递归写法写一个中序遍历
	// 中序遍历就是排升序
	//写一个_InOrder进行辅助递归
	void InOrder()
	{
		_InOrder(_root);
	}

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

		_InOrder(root->left);
		cout << root->_val << " ";
		_InOrder(root->right);
	}

	bool InsertR(const K& key)
	{
		return _InsertR(_root, key);
	}

	Node* FindR(Node* root, const K& key)
	{
		return _FindR(root, key);
	}

	bool EraseR(Node* root, const K& key)
	{
		_EraseR(root, key);
	}

private:
	bool _EraseR(Node* root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (root->_val < key)
		{
			return _EraseR(root->right, key);
		}
		else if (root->_val > key)
		{
			return _EraseR(root->left, key);
		}
		else
		{
			Node* del = root;
			if (root->left == nullptr)
			{
				root = root->right;
			}
			else if (root->right == nullptr)
			{
				root = root->left;
			}
			else
			{
				Node* min = root->right;
				while (min)
				{
					min = min->left;
				}
				swap(min->_val, del->_key);

				_EraseR(root->right, key);
			}
			delete del;
		}
	}


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

		if (root->_val < key)
		{
			return _FindR(root->right, key);
		}
		else if (root->_val > key)
		{
			return _FindR(root->left, key);
		}
		else
		{
			return root;
		}
	}

	bool _InsertR(Node*& root,const K& key)
	{
		if (root == nullptr)
		{
			root = new Node(key);
			return true;
		}

		if (root->_val < key)
		{
			return _InsertR(root->right, key);
		}
		else if (root->_val > key)
		{
			return _InsertR(root->left, key);
		}
		else
		{
			return false;
		}
	}

	Node* _root;
};


void TestBSTree()
{
	BSTree<int> t;
	int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9,5,5 };
	
	for (auto e : a)
	{
		t.Insert(e);
	}
	
	t.InOrder();
	printf("\n");
	t.Erase(5);
	t.InOrder();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值