【搜索二叉树模拟实现(带注释)-C++】

本文详细介绍了如何使用C++实现搜索二叉树的模拟,包括非递归和递归版本的插入、查找、删除等操作,并提供了中序遍历、销毁和拷贝树的功能。适合学习数据结构和算法的读者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

请添加图片描述



前言

本文总结学习搜索二叉树模拟实现-C++。


一、基本框架构建

	// 搜索二叉树节点
	template <class K, class V>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _key;
		V _val;

		BSTreeNode(K key = K(), V val = V())
			: _left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _val(val)
		{}

	};

	// 搜索二叉树模拟实现
	template <class K, class V>
	class BSTree
	{
	public:
		typedef BSTreeNode<K, V> node;

		// 构造函数
		BSTree()
			: _root(new node())
		{}
		
		// 拷贝构造 bs2(bs1)!!!!!!!!!!忘记~~~
		BSTree(const BSTree<K, V>& tree)
		{
			_root = _copyTree(tree._root);
		}

		// 赋值运算符重载(现代写法) bs2 = bs1
		BSTree<K, V>& operator=(const BSTree<K, V> tree)
		{
			std::swap(_root, tree._root);
			return *this;
		}

		// 析构函数
		~BSTree()
		{
			_Destroy(_root);
			_root = nullptr;
		}
		
	private:
		node* _root;
	};

二、成员函数实现(非递归版本)

2.1 插入元素

时复:o(n)

	bool Insert(const K& key, const V& val)
	{
		// 如果树目前为空
		if (nullptr == _root)
		{
			_root = new Node(key, val);
			return true;
		}
		
		// 如果树不为空,从根结点开始找合适的位置(不破环搜索二叉树的结构)
		// 找不到合适的位置,则插入失败
		Node* par = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key > key)
			{
				par = cur;
				cur = cur->_left;
			}
			else if(cur->_key < key)
			{
				par = cur;
				cur = cur->_right;
			}
			else
			{
				// 不允许插入相同值结点
				return false;
			}
		}

		Node* newnode = new Node(key);
		if (par->_key > key)
		{
			par->_left = newnode;
			return true;
		}
		else
		{
			par->_right = newnode;
			return true;
		}
	}

2.2 查找元素

时复:o(n)

	bool Find(const K& key)
	{
		if (nullptr == _root)
		{
			return false;
		}

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

2.3 删除元素

	// 用特殊场景套用才可以写出完整正确+画图!!!!!!!!!!
	bool Earse(const K& key)
	{
		if (nullptr == _root)
		{
			return false;
		}

		Node* par = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (key < cur->_key)
			{
				par = cur;
				cur = cur->_left;
			}
			else if (key > cur->_key)
			{
				par = cur;
				cur = cur->_right;
			}
			else
			{
				// 找到待删结点
				
				//if (nullptr == cur->_left && nullptr != cur->_right) // 叶子结点可以归并为单侧空的情况
				if (nullptr == cur->_left)
				{
					// 待删结点左为空

					// 如果待删结点为根结点,且根结点左为空
					if (nullptr == par)
					{
						_root = cur->_right;
					}
					else
					{
						if (cur == par->_left)
						{
							par->_left = cur->_right;
						}
						else
						{
							par->_right = cur->_right;
						}
					}
					delete cur;
				}
				else if(nullptr == cur->_right)
				{
					// 待删结点右为空

					// 如果待删结点为根结点,且根结点右为空
					if (nullptr == par)
					{
						_root = cur->_left;
					}
					else
					{
						if (cur == par->_left)
						{
							par->_left = cur->_left;
						}
						else
						{
							par->_right = cur->_left;
						}
					}
					delete cur;
				}
				else
				{
					// 待删节点左右都不为空,使用替换法
					
					// 1-找待删结点右子树的最小结点(即最左结点)来替换

					// 不能赋值nullptr,因为可能删的是类似下图结构的根结点!!!!!!!!!!!!!
					// 3 
					//2 4
					Node* maxpar = cur; 
					Node* maxcur = cur->_right;
					while (maxcur->_left)
					{
						maxpar = maxcur;
						maxcur = maxcur->_left;
					}

					swap(cur->_key, maxcur->_key); // 仅是交换结点的值

					// maxcur的左子树必为空,但是右子树不确定
					// 所以统一处理将maxcur的右子树链接在maxpar和maxcur相对应的一边
					if (maxcur == maxpar->_right)
					{
						maxpar->_right = maxcur->_right;
					}

					if (maxcur == maxpar->_left)
					{
						maxpar->_left = maxcur->_right;
					}

					delete maxcur;

					// 2-找待删结点左子树的最大结点来替换(同理)
				}

				return true;
			}
		}

		return false;
	}

2.4 交换节点值

void swap(node* left, node* right)
{
	std::swap(left->_key, right->_key);
	std::swap(left->_val, right->_val);
}

2.5 中序遍历

// 中序遍历
void InOrder()
{
	_InOrder(_root);
}

// 中序遍历子函数(权限为private)
void _InOrder(node* root)
{
	if (nullptr == root)
	{
		return;
	}

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

2.6 销毁

		// 销毁
		void _Destroy(node* root)
		{
			if (nullptr == root)
			{
				return;
			}

			// 后序销毁
			_Destroy(root->_left);
			_Destroy(root->_right);
			delete root; // 调用后置空
		}

2.7 拷贝树

		// 拷贝树
		node* _copyTree(node* root)
		{
			if (nullptr == root)
			{
				return nullptr;
			}

			// 深拷贝,否则会出错
			// 前序拷贝
			node* newnode = new node(root->_key, root->_val);
			newnode->_left = _copyTree(root->_left);
			newnode->_right = _copyTree(root->_right);

			return newnode;
		}

三、成员函数实现(递归版本)

3.1 插入元素

		// 插入
		bool Insert(const K& key, const V& val)
		{
			return _Insert(_root, key, val);
		}
		
		// 插入子函数(递归)
		bool _Insert(node*& root, const K& key, const V& val) // 传参_root必须要引用接收
		{
			if (nullptr == root)
			{
				// root是当前函数栈帧的root,也是上一个函数栈帧的root->左/右子节点!!!
				root = new node(key, val);
				return true;
			}

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

3.2 查找元素

		// 查找
		bool Find(const K& key)
		{
			return _Find(_root, key);
		}

		// 查找子函数(递归)
		bool _Find(node*& root, const K& key) // 传参_root必须要引用接收
		{
			if (nullptr == root)
			{
				return false;
			}
			
			// 借助搜索二叉树特性来分类递归
			if (key < root->_key)
			{
				return _Find(root->_left, key); // 加return,否则之后的递归返回值无法接收
			}
			else if (key > root->_key)
			{
				return _Find(root->_right, key); // 加return,否则之后的递归返回值无法接收
			}
			else
			{
				return true;
			}
		}

3.3 删除元素

		// 删除
		bool Erase(const K& key)
		{
			return _Erase(_root, key);
		}

		// 删除元素子函数(递归)
		bool _Erase(node*& root, const K& key) // 传参_root必须要引用接收
		{
			if (nullptr == root)
			{
				return false;
			}

			if (key < root->_key)
			{
				return _Erase(root->_left, key);
			}
			else if (key > root->_key)
			{
				return _Erase(root->_right, key);
			}
			else
			{
				// 找到待删元素
				if (nullptr == root->_key)
				{
					// 左子树为空
					root = root->_right; // root还代表着上一个栈帧中其父节点的左/右子节点!!!
					delete root;
				}
				else if (nullptr == root->_right)
				{
					// 右子树为空
					root = root->_left; // root还代表着上一个栈帧中其父节点的左/右子节点!!!
					delete root;
				}
				else
				{
					// 左右子树都不为空
					// 找其右子树最左节点
					node* minP = root;
					node* minR = root->_right;
					while (minR->_left)
					{
						minP = minR;
						minR = minR->_left;
					}

					// 交换待删节点和右子树最左节点的值
					swap(root, minR);

					// 删除
					// 此时minR左子树必为空
					if (minR == minP->_left)
					{
						minP->_left = minR->_right;
					}
					else
					{
						minP->_right = minR->_right;
					}
					delete minR;

					// 方法2:
					// 这样就可以复用删除
					// 如果在初始根节点开始使用_Erase会找不到待删节点,因为已经交换,此时整颗树不是搜索二叉树!!!~
					// 转换为在root->_left中去删除key,这里删除这个key一定会找到!!!!~
					// return _EraseR(root->_left, key);
				}
				// 统一返回
				return true;
			}
		}

总结

这里对文章进行总结:
以上就是今天总结的内容,本文包括了搜索二叉树模拟实现(带注释)-C++,分享给大家。
真💙欢迎各位给予我更好的建议,小编创作不易,觉得有用可以鼓励哦,感谢大家。peace
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。

欢迎各位大佬批评建议,分享更好的方法!!!🙊🙊🙊

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值