0
点赞
收藏
分享

微信扫一扫

idea或datagrip连接opengauss数据库

在这里插入图片描述

文章目录

🧨前言

1、二叉搜索树的基本概念?

2、二叉搜索树的节点结构组成?

template<class K>
class BSTNode
{
public:
	//构造函数,初始化列表给变量赋值
	BSTNode(const K& key)
		:_key(key)
		,_left(nullptr)
		,_right(nullptr)
	{}
public:
	K _key;
	BSTNode<K>* _left;
	BSTNode<K>* _right;
};
3、二叉搜索树的插入操作?
//插入数据函数。
bool Insert(const K& key)
{
	//首先,为空的时候,直接插入到根节点。
	if (_root == nullptr)
	{
		_root = new Node(key);
		return true;
	}

	//根节点不为空的时候,那就先从根节点开始。
	Node* cur = _root;
	Node* parent = nullptr;
	//直到为空就插入
	while (cur)
	{
		//若插入的数据值 小于 当前节点的数据值,往左走。
		if (key < cur->_key)
		{
			//临时记录当前节点的父节点,不然后面链接不上新节点。
			parent = cur;
			cur = cur->_left;
		}
		//插入的数据值 大于 当前节点的数据值,往右走。
		else if (key > cur->_key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			//走到此处说明找到一个空位置,跳出循环进行链接。
			return false;
		}
	}
	//找到cur==nullptr,此时parent节点就是最后一个节点,在插入key时候,
	//还需要判断一次,看插入的值比父节点值大,那么就当作右孩子,反之就当作左孩子。
	//由于此时cur是为空的,没必要另开空间来存储新节点,因此就把key放入该节点中
	cur = new Node(key);
	if (key < parent->_key)
	{
		//插入到左边
		parent->_left = cur;
	}
	else
	{
		//插入到右边
		parent->_right = cur;
	}
	return true;
}
4、二叉搜索树的删除操作?
	//查找函数
	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 cur;//在判断是否存在某个值的时候,直接返回true即可。
			}
		}
		return false;//说明没找到。
	}
	//删除函数
	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、右位空,左不为空;4、左右都不为空
				// 左右为空的都可以划分到其中一个为空的情况,因为当左右都为空的时候,
				//下面检测到左节点为空,则就会进入左为空的程序
				
				//左为空
				if (cur->_left == nullptr)
				{
					//先判断是否为根节点
					if (cur == _root)
					{
						//直接把节点给到根节点
						_root = cur->_right;
					}
					else if (cur == parent->_left)//若是父节点的左孩子为空,则
					//把cur->_right给到父节点的左孩子
					{
						parent->_left = cur->_right;
					}
					else//反之就是把父节点的右孩子
					{
						parent->_right = cur->_right;
					}
					delete cur;
				}

				//右为空
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else if (cur == parent->_left)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}
					delete cur;
				}

				//左右都不为空
				else
				{
					//替代法
					Node* replaceParent = cur;
					//在删除左右都不为空的时候,需要找一个节点的值来替代,可以
					//是当前节点的右子树的最左节点,也可以是当前节点左子树的最右节点,
					//下面是用的右子树的最左节点。
					Node* replace = cur->_right;
					while (replace->_left)
					{
						replaceParent = replace;
						replace = replace->_left;
					}
					//此处replace就是右子树的最左孩子节点
					//把值给到要删除的节点,即替换
					cur->_key = replace->_key;
					//此时需要判断replace节点是replaceParent节点的左孩子还是右孩子
					if (replace == replaceParent->_left)
					{
						replaceParent->_left = replace->_right;
					}
					else
					{
						replaceParent->_right = replace->_right;
					}
					delete replace;//相当于替换后,就删除替换的那个节点
				}
				return true;
			}
		}
		//没找到就返回false
		return false;
	}
5、二叉搜索树的遍历?

下面把三种遍历方式都写出来:

//中序遍历搜索二叉树
void _InOrder(Node* root)
{
	if (root == nullptr)
	{
		return;
	}

	//左 根 右
	_InOrder(root->_left);
	cout << root->_key<<" ";
	_InOrder(root->_right);
}

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

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

运行结果如下:
在这里插入图片描述

6、二叉搜索树的性能分析?

为避免性能下降,通常使用平衡二叉搜索树,如AVL树或红黑树,以保证树的高度始终接近O(log n)。后续文章会讲述。

🎉完整代码如下:
#pragma once

#include<iostream>
using namespace std;

namespace N
{
	//先创建二叉树结构
	template<class K>
	class BSTNode
	{
	public:
		//构造函数
		BSTNode(const K& key)
			:_key(key)
			,_left(nullptr)
			,_right(nullptr)
		{}
	public:
		K _key;
		BSTNode<K>* _left;
		BSTNode<K>* _right;
	};

	template<class K>
	class BSTree
	{
		typedef BSTNode<K> Node;
	public:
		//插入数据函数
		bool Insert(const K& key)
		{
			//首先,为空的时候,直接插入到根节点
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}

			//根节点不为空的时候,那就先从根节点开始
			Node* cur = _root;
			Node* parent = nullptr;
			//直到为空就插入
			while (cur)
			{
				//若插入的数据小于节点的数据值,往左走
				if (key < cur->_key)
				{
					//记录下一节点的父节点
					parent = cur;
					cur = cur->_left;
				}
				//大于节点的值
				else if (key > cur->_key)
				{
					parent = cur;
					//往右边走
					cur = cur->_right;
				}
				//相等就返回
				else
				{
					return false;
				}
			}
			//找到cur==nullptr,此时parent节点就是最后一个节点,在插入key时候,
			//还需要判断一次,比父节点值大,就插入到右孩子处,反之就左孩子
			//由于cur是为空的,因此把key放入该节点中
			cur = new Node(key);
			if (key < parent->_key)
			{
				//插入到左边
				parent->_left = cur;
			}
			else
			{
				//插入到右边
				parent->_right = cur;
			}
			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 = 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、右位空,左不为空;4、左右都不为空
					// 左右为空的都可以划分到其中一个为空的情况,因为当左右都为空的时候,
					//下面检测到左节点为空,则就会进入左为空的程序
					
					//左为空
					if (cur->_left == nullptr)
					{
						//先判断是否为根节点
						if (cur == _root)
						{
							//直接把节点给到根节点
							_root = cur->_right;
						}
						else if (cur == parent->_left)//若是父节点的左孩子为空,
						//则把cur->_right给到父节点的左孩子
						{
							parent->_left = cur->_right;
						}
						else//反之就是把父节点的右孩子
						{
							parent->_right = cur->_right;
						}
						delete cur;
					}

					//右为空
					else if (cur->_right == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else if (cur == parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
						delete cur;
					}

					//左右都不为空
					else
					{
						//替代法
						Node* replaceParent = cur;
						//在删除左右都不为空的时候,需要找一个节点的值来替代,
						//可以是当前节点的右子树的最左节点
						Node* replace = cur->_right;
						while (replace->_left)
						{
							replaceParent = replace;
							replace = replace->_left;
						}
						//此处replace就是右子树的最左孩子节点
						//把值给到要删除的节点,即替换
						cur->_key = replace->_key;
						//此时需要判断replace节点是replaceParent节点的左孩子还是右孩子
						if (replace == replaceParent->_left)
						{
							replaceParent->_left = replace->_right;
						}
						else
						{
							replaceParent->_right = replace->_right;
						}
						delete replace;//相当于替换后,就删除替换的那个节点
					}
					return true;
				}
			}
			//没找到就返回false
			return false;
		}

		void InOrder()
		{
			_InOrder(_root);
		}

		void PrevOrder()
		{
			_PrevOrder(_root);
		}

		void PostOrder()
		{
			_PostOrder(_root);
		}
	private:
		//中序遍历搜索二叉树
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}

			//左 根 右
			_InOrder(root->_left);
			cout << root->_key<<" ";
			_InOrder(root->_right);
		}

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

		void _PostOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			_InOrder(root->_right);	
			cout << root->_key << " ";
		}
	private:
		//BSTNode<K>* _root=nullptr;//定义根节点
		Node* _root = nullptr;
	};
}
举报

相关推荐

0 条评论