二叉搜索树——迭代实现


普通的树形结构中数据是杂乱无章的,实际意义不大,要想更好的管理数据,需要让数据有序,二叉搜索树又称二叉排序树 ,是一种特殊的树形结构。

规定一般的二叉搜索树的左节点小于父节点,右节点大于父节点,节点均不相等
图例:

学习一种数据结构,自然要学会模拟实现它的增删查改啦,废话不多说,开始手撕搜索树吧。

(完整代码已放至gitee,按需参考,如有错误欢迎指出)

https://gitee.com/chxchenhaixiao/test_c/commit/4b77962a29e603679f9d21ecabdd87cb5a15e5e5

一、定义节点结构

这一步非常简单,不需要过多思考

cpp 复制代码
template<class K>
struct BSTreeNode{

	K _key;
	BSTreeNode* left;
	BSTreeNode* right;
	
	BSTreeNode(K key)
		:_key(key)
		,left(nullptr)
		,right(nullptr)
	{}	//不要忘记写构造函数
};

二、定义搜索二叉树类

cpp 复制代码
template<class K>
class BSTree{
private:	//protected:也可
	typedef BSTreeNode Node;//定义内部类型
	Node* _root=nullptr; //只需要存根节点
	//......
public:
	//......
};

三、查找实现

也非常简单,严格遵守二叉搜索树特征

如果目标值小于当前值,左走
如果目标值大于当前值,右走
如果当前值为空,则找不到

cpp 复制代码
bool Find(const K& key){
	Node* cur = _root;
	while(cur){
		if(key<cur->_Key)
			cur=cur->left;
		else if(key>cur->_key)
			cur=cur->right;
		else
			return true;
	}
	return false;
}

四、插入实现

情形一:

当前节点数为0,直接更新_root即可

情形二:

当前节点数大于0,需要找到符合要求的位置

cpp 复制代码
bool Insert(const K& key){
	Node* node = new Node(key);
	Node* prev=nullptr;	//需要记录前一个位置方便链接新节点
	Node* cur=_root;
	if(_root==nullptr)
		_root=node;
	else{
		while(cur){
			prev=cur;
			if(key<cur->_key)
				cur=cur->left;
			else if(key>cur->right)
				cur=cur->right;
			}
			else
				return false;
		//
		if(prev->left==cur)
			prev->left=node;
		else
			prev->right=node;
		/*这一步很重要,一定要进行判断所找到的空
		节点是在prev的左还是右*/
	}
	return true;
}

五、删除实现

删除的情形可以分为三种:
1、目标节点为叶子节点:

2、目标节点只有单个孩子节点:

3、目标节点左右孩子均存在:

针对不同的情形,要采取不同的方式

对于第一种情况,只需要将目标节点的父节点中的一个指针置为空

对于第二种情况,需要将目标节点的孩子节点交给父节点

加入把空指针也算作一个节点,那么前两种情形即可归并为一类

对于第三种情况,不能像前两种一样了,而是需要寻找目标节点右(左)子树的最小(大)节点与目标节点交换,再将问题转变为前两种情形

cpp 复制代码
bool Erase(const K& key) {
		if (Find(key) == false)
			return false;
		
		Node* cur = _root;
		Node* prev = nullptr;
		
		while (key != cur->_key) {
			prev = cur;
			if (key < cur->_key) {
				cur = cur->left;
			}
			else {
				cur = cur->right;
			}
		}
		
		if (cur->left == nullptr) {
			if (prev == nullptr) {
				_root = cur->right;
			}
			else {
				if (prev->left == cur) {
					prev->left = cur->right;
				}
				else {
					prev->right = cur->right;
				}
			}
			delete cur;
		}
		else if (cur->right == nullptr) {
			if (prev == nullptr) {
				_root = cur->left;
			}
			else {
				if (prev->left == cur) {
					prev->left = cur->left;
				}
				else {
					prev->right = cur->left;
				}
			}
			delete cur;
		}
		else {
			Node* MinRight = cur->right;
			Node* pMinRight = cur;
			while (MinRight->left) {
				pMinRight = MinRight;
				MinRight = MinRight->left;
			}
			cur->_key = MinRight->_key;
			
			if (pMinRight->left == MinRight)
				pMinRight->left = MinRight->right;
			else {
				pMinRight->right = MinRight->right;
			}
			
			delete MinRight;
		}
		return true;
	}

几个易错点:
1、

不要忘记这里的判断,如果没有这一句,

当删除一颗歪脖树的根节点会崩溃

2、

pMinRight的初值不可以为空

否则删除10时,pMinRight不会得到更新,会导致运行崩溃
3、

这里的判断少不得,可以不要以为目标节点的右子树一定是链接在父节点的左边

也许目标节点的父节点是根节点

(删除8时就需要将10的右树链接在pMinRight右)

相关推荐
『六哥』37 分钟前
Windows 10 如何设置右击鼠标快速进行“关机”
windows·经验分享·编辑器
odoo-卜永1 小时前
ubuntu22.04连接爱普生打印机型号L385
linux·经验分享·ubuntu
lulinhao1 小时前
HCIA/HCIP基础知识笔记汇总
网络·笔记
杉之2 小时前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
云 无 心 以 出 岫2 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
渗透测试老鸟-九青2 小时前
面试经验分享 | 成都渗透测试工程师二面面经分享
服务器·经验分享·安全·web安全·面试·职场和发展·区块链
WarPigs2 小时前
blender场景导入Unity的流程(个人总结)
笔记
换一颗红豆3 小时前
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
c++
随便昵称3 小时前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
commonbelive3 小时前
团体程序设计天梯赛——L1-100 四项全能
c++