数据结构 【搜索二叉树】

server/2025/2/28 11:38:10/

        搜索二叉树是STL中map和set的重要铺垫,学好搜索二叉树有助于理解map和set的特性。搜索二叉树也是一种二叉树结构,只是多了一些特定的性质。

        一棵搜索二叉树可以为空树,如果不为空时,一定满足下面的性质。

  • 若它的左子树不为空,则所有左子树上的节点都小于根节点的键值。
  • 若它的右子树不为空,则所有的右子树上的节点都大于根节点的键值。
  • 它的左右子树也分别为搜索二叉树。

         基于先描述在组织的思想,我们可以尝试搭建一个搜索二叉树结构。

1、框架搭建

        先描述具体的节点,再进行节点间的组织链接。

template<class K>
class BSTreeNode
{
public:BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:BSTree():_root(nullptr){}
private:Node* _root;
};

        框架构造还是六个字:先描述,再组织。

2、节点插入

        数据进行插入时要分情况讨论:

  1. 搜索二叉树为空时,可以直接插入;
  2. 不为空时,如果插入的键值大于根节点就去根节点的右边继续寻找位置进行插入,如果插入的键值小于根节点就去根节点的左边寻找位置进行插入;如果搜索二叉树种存在要插入的键值就返回false;
	bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}else{//搜索二叉树不为空Node* parent = _root;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{return false;}}//判断链接在左还是链接在右cur = new Node(key);cur->_key > parent->_key ? parent->_right = cur : parent->_left = cur;return true;}}

      在寻找空位置的过程中,也要同时记录当前节点的父节点位置。主要是方便进行后面的链接。

3、中序遍历

        由于中序遍历需要传入当前节点的地址进行递归,这里为了方便外部的对象调用。对中序遍历进行了一次封装。在封装之后的函数内部传入_root;

//省略类域	void InOrder(){_InOrder(_root);cout << endl;}
private:void _InOrder(Node* root)
{if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}

        对上述代码进行简单的测试:

#include<iostream>
using namespace std;
#include"BinarySearchTree.h"void TestBSTree()
{int arr[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };BSTree<int> bs;for (auto e : arr){bs.Insert(e);}bs.InOrder();}int main()
{TestBSTree();return 0;
}

        运行结果:

 4、节点删除

        节点的删除比较复杂。需要分下面的情况进行分析:

  • 要删除的节点没有子节点,可以直接进行删除,再删除之后要对它的父节点的位置进行置空操作。

  • 如果要删除的节点只有一个子节点,同样也可以直接删除,在删除之后需要在进行判断,如果删除节点的子节点小于删除节点的父节点,那么就链接在父节点的左边;反之,就连接在右边。

  • 如果要删除的节点左右子树都非空树,那么这时就需要进行替换删除。为了保证替换后的树形结构仍然满足搜索二叉树的性质,这时的替换要求为:只能和删除节点的左子树的最右节点或者右子树的最左节点进行替换。通常情况下使用左子树的最右节点进行替换。

上面的1和2可以归纳为一点,当删除的节点的左子树为空树时,就将删除节点的父节点链接上删除节点的右节点;反之,就将删除节点的父节点链接上删除节点的左节点。

	bool Erase(const K& key){Node* parent = _root;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.左子树为空if (cur->_left == nullptr){if (cur == _root){_root = _root->_right;}else{//判断删除节点的位置,进行原位置链接if (parent->_left == cur){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}//2.右子树为空else if (cur->_right == nullptr){if (cur == _root){_root = _root->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}//3.左右子树都不为空else{Node* leftMaxParent = cur;Node* leftMax = cur->_left;//寻找左子树的最右节点 且找到它的父节点while (leftMax->_right){leftMaxParent = leftMax;leftMax = leftMax->_right;}std::swap(cur->_key, leftMax->_key);if (leftMaxParent->_left == leftMax){leftMaxParent->_left = leftMax->_left;}else{leftMaxParent->_right = leftMax->_left;}//下面统一删除cur;cur = leftMax;}delete cur;cur = nullptr;return true;}}return false;}


http://www.ppmy.cn/server/171282.html

相关文章

7 天精通 DeepSeek 实操手册

挑战目标 从零基础开始&#xff0c;用 7 天时间&#xff0c;精通 DeepSeek 实操。 对零基础的同学来说&#xff0c;要全部完成这个挑战并不容易。因此&#xff0c;我们提供了每天的学习目标和实操任务&#xff0c;并提供三大锦囊助你一臂之力&#xff1a; 针对常见问题的解决…

P9420 [蓝桥杯 2023 国 B] 双子数--最高效的质数筛【埃拉托斯特尼筛法】

P9420 [蓝桥杯 2023 国 B] 双子数 题目 分析代码 题目 分析 首先&#xff0c;我们如何找到双子数&#xff1f; 1&#xff09;找到所有质数满足范围内的质数&#xff08;即至少质数^2<23333333333333) 我们看见双子数x的范围2333<x<23333333333333&#xff0c;又因为…

大模型系列——专家混合模型 (MoE)快速指南

大模型系列——专家混合模型 (MoE)快速指南 专家混合 (MoE) 已成为一种流行的提高 LLM 效率的架构组件。在这篇博文中,我们将探讨研究人员在实现专家完美混合的道路上所采取的步骤。 专家混合 (MoE) 已成为一种流行的提高 LLM 效率的架构组件。在这篇博文中,我们将探讨研究人…

常用的HTML meta标签有哪些

meta是 HTML 中的一个元数据标签&#xff0c;位于 <head> 标签内&#xff0c;不会在页面上直接显示&#xff0c;但能为浏览器和搜索引擎提供关于网页的重要信息。以下是一些常用的 <meta> 标签及其用途&#xff1a; 1. 字符编码声明 用于指定 HTML 文档的字符编码…

深度学习实战:使用TensorFlow构建卷积神经网络(CNN)

在前两篇文章中&#xff0c;我们从零开始构建了简单的神经网络&#xff0c;并逐步扩展到多层神经网络。这些网络在处理简单的数据集&#xff08;如鸢尾花数据集&#xff09;时表现出色。然而&#xff0c;对于更复杂的任务&#xff0c;如图像分类&#xff0c;我们需要更强大的模…

Python代码片段-断点任务

使用Python处理一堆长耗时任务的时候&#xff0c;为了防止异常退出程序或者手动退出程序后丢失任务进度&#xff0c;可用使用断点的方式记录任务进度&#xff0c;下次重载任务后&#xff0c;继续运行上次未完成的任务即可。 这里用json文件作为数据持久化的方式&#xff0c;免…

信号在linux内核的表示

在Linux内核中&#xff0c;信号的表示和处理机制是进程间通信和进程控制的重要组成部分。以下是信号在Linux内核中的表示及相关机制的详细说明&#xff1a; 1. 信号在内核中的表示 在Linux内核中&#xff0c;每个信号有三个关键属性&#xff1a; 阻塞标志&#xff08;Block&…

使用 Polars 进行人工智能医疗数据分析(ICU数据基本测试篇)

引言 在医疗领域&#xff0c;数据就是生命的密码&#xff0c;每一个数据点都可能蕴含着拯救生命的关键信息。特别是在 ICU 这样的重症监护场景中&#xff0c;医生需要实时、准确地了解患者的病情变化&#xff0c;以便做出及时有效的治疗决策。而随着医疗技术的飞速发展&#x…