二叉搜索树——迭代实现


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

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

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

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

相关推荐
落羽的落羽22 分钟前
【落羽的落羽 数据结构篇】栈和队列
c语言·数据结构
qy发大财37 分钟前
分发糖果(力扣135)
数据结构·算法·leetcode
微刻时光1 小时前
影刀RPA中级证书-Excel进阶-开票清单
经验分享·python·低代码·rpa·影刀·影刀证书·影刀实战
ChoSeitaku1 小时前
12.重复内容去重|添加日志|部署服务到Linux上(C++)
linux·c++·windows
挣扎与觉醒中的技术人1 小时前
网络安全入门持续学习与进阶路径(一)
网络·c++·学习·程序人生·安全·web安全
滴_咕噜咕噜1 小时前
C#基础总结:常用的数据结构
开发语言·数据结构·c#
haaaaaaarry1 小时前
【分治法】线性时间选择问题
数据结构·算法
CS创新实验室1 小时前
计算机考研之数据结构:P 问题和 NP 问题
数据结构·考研·算法
OTWOL2 小时前
【C++编程入门基础(一)】
c++·算法
宇寒风暖2 小时前
侯捷 C++ 课程学习笔记:内存管理与工具应用
c++·笔记·学习