二叉搜索树——迭代实现


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

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

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

(完整代码已放至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右)

相关推荐
好奇龙猫3 分钟前
【大学院-筆記試験練習:线性代数和数据结构(16)】
数据结构·线性代数·决策树
小尧嵌入式3 分钟前
【Linux开发五】条件变量|信号量|生产者消费者模型|信号概念和常见信号|信号的使用和处理
linux·运维·服务器·开发语言·c++·嵌入式硬件
一碗甜汤ᐝ5 分钟前
论文阅读笔记-FastVLM: Efficient Vision Encoding for Vision Language Models
论文阅读·笔记·语言模型
智者知已应修善业6 分钟前
【输出方形点阵】2024-11-1
c语言·c++·经验分享·笔记·算法
hope_wisdom9 分钟前
C/C++数据结构之用数组实现队列
c语言·数据结构·c++·队列
BlackWolfSky10 分钟前
鸿蒙中级课程笔记3—ArkUI进阶3—给应用添加交互(手势)
笔记·华为·交互·harmonyos
近津薪荼13 分钟前
优选算法——双指针专题2(模拟)
c++·学习·算法
「QT(C++)开发工程师」13 分钟前
C++设计模式
开发语言·c++·设计模式
Tina Tang18 分钟前
Agentic AI学习笔记(5)
笔记·学习
爱莉希雅&&&19 分钟前
Docker 超详细全量笔记(含参数解释)
linux·运维·服务器·笔记·docker·容器