【C++】二叉搜索树|Key模型|key_value模型|基本操作

目录

​编辑

二叉搜索树的定义,创建(Key模型)

定义

创建

 基本操作

插入

查找

删除

Key模型和Key_Value模型 

二叉搜索树(Key_Value模型) 

定义

创建

基本操作

 插入

 应用


二叉搜索树的定义,创建(Key模型)

定义

BST = BinarySearchTree

每个节点包含一个键(key)和两个指针,分别指向其左子树和右子树。

  • 左子树上的所有节点的键值都小于其父节点的键值。
  • 右子树上的所有节点的键值都大于其父节点的键值。
  • 每个子树也是一棵二叉搜索树。

 

创建

 定义一个模板类BSTreeNode

  • 用于表示二叉搜索树中每个节点的结构,包含指向左右子节点的指针以及节点存储的关键字。

同时定义另一个模板类BSTree

  • 使用BSTreeNode来构成实际的二叉搜索树结构,包含对树根节点的引用。
// 定义一个模板类,用于表示二叉搜索树的节点
template<class K>
struct BSTreeNode
{// 指向左子节点的指针BSTreeNode<K>* _left;// 指向右子节点的指针BSTreeNode<K>* _right;// 节点存储的关键字K _key;// 构造函数,初始化节点的关键字,并将左右子节点指针设为nullptrBSTreeNode(const K& key):_left(nullptr)  // 初始化左子节点指针为nullptr, _right(nullptr) // 初始化右子节点指针为nullptr, _key(key)       // 初始化节点关键字{}
};// 定义一个基于BSTreeNode<K>的二叉搜索树类模板
template<class K>
class BSTree
{// 为方便起见,定义一个类型别名,代表BSTreeNode<K>类型typedef BSTreeNode<K> Node;private:// 指向二叉搜索树根节点的指针,默认初始化为nullptrNode* _root = nullptr;
};

 基本操作

插入

将一个新的键值插入到BSTBinary Search Tree)中,保持BST的特性。

具体过程:

  • 树为空,则直接新增节点,赋值给root指针
  • 树不空,按二叉搜索树性质查找插入位置,插入新节点 

// 插入函数,将给定的关键字插入到二叉搜索树中
bool Insert(const K& key)
{// 判断树是否为空,若为空则直接在根节点插入新节点并返回trueif (_root == nullptr){_root = new Node(key);return true;}// 初始化父节点指针和当前遍历节点指针   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;}// 遇到相同关键字,二叉搜索树不允许数据冗余,返回falseelse{return false;}}// 创建新节点,初始化关键字Node* node = new Node(key);// 将新节点插入到父节点的适当子树(根据大小决定是左子树还是右子树)if (parent->_key < key){parent->_right = node;}else{parent->_left = node;}// 插入成功,返回truereturn true;
}

首先检查树是否为空,然后通过循环比较找到插入位置。

如果遇到相同关键字的节点,则因为二叉搜索树的性质不可冗余(每个节点的关键字都大于其左子树中所有节点的关键字且小于其右子树中所有节点的关键字),插入失败并返回false。

否则,找到合适的空位后创建新节点并插入到树中,最后返回true表示插入成功。

查找

查找BST中是否存在一个特定的键值;

基于二叉搜索树的结构的特点:左节点小于根,右节点大于根

  • 从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
  • 最多查找高度次,走到到空,还没找到,这个值不存在。

// 查找函数,判断二叉搜索树中是否存在给定的关键字
bool Find(const K& key)
{// 如果树的根节点为空,说明树为空,直接返回false表示未找到if (_root == nullptr){return false;}// 初始化当前遍历的节点为根节点Node* cur = _root;// 在树中循环查找关键字while (cur){// 如果当前节点的关键字小于待查找关键字,转向右子节点继续查找if (cur->_key < key){cur = cur->_right;}// 如果当前节点的关键字大于待查找关键字,转向左子节点继续查找else if (cur->_key > key){cur = cur->_left;}//找到了匹配的键 ,返回trueelse{return true;}}// 循环结束未找到匹配的键,返回falsereturn false;
}

在二叉搜索树中查找给定的关键字是否存在。

  • 从树的根节点开始,根据比较结果沿着左子树或右子树进行递归查找。
  • 如果找到关键字相同的节点,则返回true;
  • 如果遍历完所有可能的路径仍未找到,则返回false;表示该关键字不在树中。

删除

从BST中删除一个键值,并重新组织树以保持BST的特性。

如果找到了要删除的节点,接下来需要根据该节点的子节点数量来决定删除策略:

叶子节点:

  • 直接删除该节点。

一个子节点:

  • 判断该子节点在待删除的节点左右子树,根据其来用待删除节点的父节点链接其子节点;

两个子节点:

  • 在待删除节点的左右子树找其替换节点(在左子树寻找最大节点或者在右子树寻找最小节点),替换后,让其链接到原待删除节点的父节点合适的位置上。

注:叶子节点和一个子节点可以整合到一起处理;

 

// 删除函数,从二叉搜索树中删除给定值的节点
bool Erase(const K& val)
{// 初始化当前节点指针和父节点指针Node* cur = _root;Node* parent = nullptr;// 查找要删除的节点while (cur){// 根据键值比较结果在树中向下搜索if (cur->_key < val){parent = cur;cur = cur->_right;}else if (cur->_key > val){parent = cur;cur = cur->_left;}// 找到要删除的节点else{// 处理三种情况:叶子节点、只有左子节点、只有右子节点、左右子节点均存在//叶子节点和只有一个子节点 可一起处理// 情况1:当前节点没有左子节点if (cur->_left == nullptr){if (cur == _root)      // 如果是根节点    删除根节点需要更新根节点的指向{_root = cur->_right;}// 更新父节点的子指针以绕过被删除节点else if (parent->_left == cur){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;}// 情况2:当前节点没有右子节点else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else if (parent->_left == cur){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}// 情况3:当前节点左右子节点均不为空else{// 找到右子树中的最小节点及其父节点Node* rightMinParent = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}// 将要删除节点的值替换为右子树中的最小值,然后删除那个最小值节点std::swap(cur->_key, rightMin->_key);// 更新最小值节点的父节点的子指针,绕过被删除的最小值节点if (rightMinParent->_left == rightMin){rightMinParent->_left = rightMin->_right;}else{rightMinParent->_right = rightMin->_right;}//释放待删除节点资源delete rightMin;}// 删除操作完成,返回truereturn true;}}// 未找到要删除的值,返回falsereturn false;
}

首先通过循环查找要删除的节点;

然后根据节点的子节点情况执行不同的删除逻辑:

  • 叶子节点和只有一个子节点时,用该子节点替换删除节点的位置;
  • 有两个子节点时,找到右子树的最小节点,用其值替换待删除节点的值,然后删除右子树中的这个最小节点。

最后,根据删除操作的结果返回true或false。

Key模型和Key_Value模型 

两种不同的数据存储和检索方式

Key模型

  •  Key模型通常指的是数据结构中只关注唯一标识符(Key)的一种简单模式,在这种模型下,通过唯一的Key来识别和访问,不直接关联任何值或者额外信息。

例如:

        给出一个单词,判断是否拼写正确,只需要将所有单词存储后,进行搜索判断,存在就正确,不存在就错误。

Key_Value模型 

  • 一种数据存储模型,其中每个条目由两部分组成:一个Key(键)和一个与之对应的Value(值) 

例如:

        同样给出一个单词,但是输出的是其中文意思,一种对应关系。

二叉搜索树(Key_Value模型) 

定义

每个节点包含三个部分:一个键(Key),一个值(Value),以及两个指向其子节点的指针(分别指向左子树和右子树)。

创建

每个节点不仅包含一个key用于维持树的排序特性,还包含一个与key相对应的value

// 定义一个模板类,表示二叉搜索树的节点,支持键值对(Key-Value)模型
template<class K, class V>
struct BSTreeNode
{// 指向左子节点的指针BSTreeNode<K, V>* _left;// 指向右子节点的指针BSTreeNode<K, V>* _right;// 节点存储的键(Key)K _key;// 节点存储的值(Value)V _value;// 构造函数,接收键和值作为参数,初始化节点的键和值,并将左右子节点指针设为nullptrBSTreeNode(const K& key, const V& value):_left(nullptr)  // 初始化左子节点指针为nullptr, _right(nullptr)        // 初始化右子节点指针为nullptr, _key(key)         // 初始化节点的键, _value(value)     // 初始化节点的值{}
};// 定义一个基于BSTreeNode<K, V>的二叉搜索树类模板
template<class K, class V>
class BSTree
{// 重命名,简化BSTreeNode<K, V>typedef BSTreeNode<K, V> Node;public:    //操作,比如 删除,插入等
private:   // 树的根节点指针,默认初始化为nullptrNode* _root = nullptr;
};

基本操作

 插入

其实只有一些细微的差别,

// 插入函数,向二叉搜索树中添加一个新的键值对
bool Insert(const K& key, const V& value)
{// 如果树为空(根节点为nullptr),则创建一个新的节点作为根节点if (_root == nullptr){_root = new Node(key, value);return true; // 插入成功}// 初始化父节点指针和当前遍历的节点指针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;}// 如果键已经存在于树中,则不允许插入重复键,返回falseelse{return false;}}// 创建新节点,使用传入的键和值进行初始化cur = new Node(key, value);// 将新节点插入到找到的正确位置,根据父节点的键与新节点键的比较结果决定是左子节点还是右子节点if (parent->_key < key){parent->_right = cur; // 插入为右子节点}else{parent->_left = cur; // 插入为左子节点}return true; // 插入操作成功完成
}

 应用

根据输入的单词,输出对应中文意思;

void TestBSTree(){BSTree<string, string> dict;dict.Insert("string", "字符串");dict.Insert("left", "左边");dict.Insert("insert", "插入");//...string str;while (cin >> str){BSTreeNode<string, string>* ret = dict.Find(str);if (ret){cout << ret->_value << endl;}else{cout << "无此单词,请重新输入" << endl;}}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/33434.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第二十九篇——交叉验证:电信诈骗为什么能成功?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 具体的应用中&#xff0c;让我理解了交叉验证的重要意义&#xff0c;他也…

【Altium】查找PCB上未连接的网络

【更多软件使用问题请点击亿道电子官方网站】 1、文档目标&#xff1a; PCB设计后期检查中找出没有连接的网络 应用场景&#xff1a;PCB设计后期&#xff0c;需要检查是否所有网络都已连接布线。虽然未连接的网络会有飞线显示&#xff0c;但是由于布线后期整板布线密度较高&…

如何优雅的删库跑路?

本文已收录于&#xff1a;https://github.com/danmuking/all-in-one&#xff08;持续更新&#xff09; 前言 哈喽&#xff0c;大家好&#xff0c;我是 DanMu。鲁迅说过&#xff1a;一个程序员成熟的标志是一次优雅是删库。&#xff08;鲁迅&#xff1a;这bi话我可没说过&#x…

LeetCode刷题之HOT100之排序链表

2024/6/24 周末两天没去实验室&#xff0c;可能跟天气有关&#xff0c;也可能跟我不想去有关。最近实在太热&#xff0c;不想出门。早上来&#xff0c;去二楼看了一下我的栀子花&#xff0c;长得很好&#xff0c;但是花苞都没了&#xff0c;只剩下唯一一颗&#xff0c;给它浇了…

vue3滚动日历选择器

倒叙日历&#xff1a; <template><div class"date-picker"><div class"column" wheel"onYearScroll"><div v-for"(year, index) in displayedYears" :key"index" :class"{current: year current…

Ubuntu下载QT5.8安装包-bestswinger课程

最近在看UP的QT开发课&#xff0c;真的找了巨久这个安装包&#xff0c;谁都不想在安装上花太多时间。。出一版小小教程吧&#xff5e; 首先打开qt download官网&#xff0c;5.8好像在镜像网站上没有看到&#xff0c;所以我最后还是老老实实官网了&#xff0c;而且5.8会小一点 …

Linux 运维 | 4.从零开始,文件目录特殊权限管理实践

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] 0x00 前言简述 描述&#xff1a;前一章&#xff0c;学习了Linux系统中的用户与用户组的管理&#xff0c;此章节我们将继续学习Linux系统中比较基础且重要的文件权限设置与属性管理&#xff0c;在L…

解锁流量密码:这些软文新闻稿发布平台值得一试

随着互联网技术的飞速发展&#xff0c;软文新闻作为一种有效的品牌传播和营销推广手段&#xff0c;越来越受到企业和个人的重视。而新闻稿发布平台也已成为企业、机构和个人传递信息、展示形象的重要渠道。所以选择一个合适的软文新闻稿发布平台&#xff0c;则成为实现信息快速…

日牵物流装备受邀盛装亮相2024长三角快递物流供应链与技术装备展览会(杭州)

日牵物流装备受邀盛装亮相2024长三角快递物流供应链与技术装备展览会&#xff0c;为物流节省每一个铜板&#xff0c;3C馆A21与您相约&#xff01; 日牵物流装备始建于1995年&#xff0c;总部坐落于辽宁省大连市&#xff0c;是一家集科研开发、生产制造、销售服务于一体的现代化…

【数据结构与算法 经典例题】使用栈实现队列(图文详解)

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法 经典例题》C语言 期待您的关注 目录 ​​一、问题描述 二、前置知识 三、解题思路 原理&#xff1a; 图解&…

警惕!马斯克深度伪造视频引发的加密货币骗局泛滥

近期&#xff0c;一场以埃隆马斯克形象为幌子的深度伪造视频骗局在网络世界掀起了轩然大波&#xff0c;给广大网民带来了巨大的困扰和潜在的经济损失。 据可靠消息&#xff0c;埃隆・马斯克的深度伪造视频在 YouTube 直播平台上频繁出现&#xff0c;成为了不法分子实施加密货币…

大型语言模型(LLM)和多模态大型语言模型(MLLM)的越狱攻击

随着大型语言模型&#xff08;LLMs&#xff09;的快速发展&#xff0c;它们在各种任务上表现出了卓越的性能&#xff0c;有效地遵循指令以满足多样化的用户需求。然而&#xff0c;随着这些模型遵循指令的能力不断提升&#xff0c;它们也越来越成为对抗性攻击的目标&#xff0c;…

【大数据】Hadoop学习笔记

基本概念 Hadoop组成 HDFS: Hadoop分布式文件存储系统, 在Haddop中处于底层/核心地位YARN: 分布式通用的集群资源管理系统和任务调度平台, 支撑各种计算引擎执行MapReduce: 第一代分布式计算引擎, 但因为部分原因, 许多企业都不直接使用MapReduce, 但许多底层软件仍然在使用Ma…

RabbitMQ 开发指南

连接RabbitMQ 连接方式一&#xff1a; 也可以选择使用URI的方式来实现 连接方式二&#xff1a; Connection接口被用来创建一个Channel&#xff0c;在创建之后&#xff0c;Channel可以用来发送或者接收消息。 Channel channel conn.createChannel();使用交换器和队列 声明…

汽车抬头显示器HUD阳光倒灌实验太阳光模拟器

简述 HUD阳光倒灌实验是评估汽车抬头显示器&#xff08;HUD&#xff09;在强烈日照条件下的性能表现的一种测试方法。该实验通过模拟太阳光照射&#xff0c;检测HUD在阳光直射下的显示效果&#xff0c;以确保驾驶者在强烈日照下仍能清晰地看到HUD显示的信息&#xff0c;从而提…

CentOS配置本地yum源

版本说明 操作系统版本&#xff1a;CentOS7.9 虚拟机版本 虚拟机打快照 首先给虚拟机打个快照&#xff0c;点击图下所示位置 命名快照之后&#xff0c;点击拍摄快照 可以参考图下所示进行管理和恢复快照 迁移原有yum源 先进入到/etc/yum.repos.d/ &#xff0c;可以看到有很多…

C++编程(一)C++与C语言的一些区别

文章目录 一、QtCreator基本使用&#xff08;一&#xff09;编码格式&#xff1a;&#xff08;二&#xff09;C编程1. 文件后缀2. 编译3. 头文件 二、名字空间&#xff08;一&#xff09;概念以及访问方式1. 概念2. 访问方式&#xff08;1&#xff09;通过作用域限定符进行访问…

手写方法实现字符串例如:“123“与整型例如:123相互转化(面试必会)

目录 二、字符串类型转化为整型 1. 初始化变量 2.定义字符串索引值 3.思考如何将字符1转化为数字1 4. 转化思路 5.考虑字符串转化负数例&#xff1a;-123456 6.完整代码 四、最后 一、前言 在c语言和c中&#xff0c;有许许多多的数据类型相互转化的方法&#xff0c;这里…

【面试题】面试小技巧:如果有人问你 xxx 技术是什么?_面试问你对什么技术特别了解

前端工程越来越大&#xff0c;前面几种方案不能很好的支持单元测试。 在这样的背景下&#xff0c;React 诞生了。React 带来了新的思维模式&#xff0c;UI fn(props)&#xff0c;React 中一个组件就是一个函数或者一个类&#xff0c;一个函数或者一个类就是一个基础单位&…

msvcp120.dll丢失的解决方法,总结几种有效的解决方法

最近&#xff0c;我在使用计算机时遇到了一个问题&#xff0c;系统提示我丢失了msvcp120.dll文件。这让我感到非常困扰&#xff0c;因为这个问题导致我无法正常运行一些程序。经过一番搜索和尝试&#xff0c;我找到了几种修复这个问题的方法&#xff0c;并成功解决了这个问题。…