数据结构:搜索二叉树

前言

在前面我们已经学习了二叉树的基础操作,但是,仅仅是二叉树,没有太大的作用啊,存数据效果没有顺序表和链表好,那为啥还要学二叉树呢?
这不就来了嘛,给二叉树增加一些性质,作用不就出来了嘛。
本篇文章将介绍二叉树的进阶版本,给二叉树增加了搜索特性,搜索二叉树

搜索二叉树的概念和性质

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
1. 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2. 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树

在这里插入图片描述

注意:要求整棵左子树的值都小于根节点的值,而不仅仅是要求左节点的值小于根节点的值,对于右子树也是如此

ps:当然也可以处理成左子树大,右子树小,不过普遍来说,都是构成左子树小,右子树大的。


搜索二叉树的操作

这里我们先给一个数组,用这个数组的数据构成搜索二叉树
在这里插入图片描述

搜索二叉树的遍历

根据搜索二叉树的性质,我们知道,左子树的值全部都小于根节点的值,右子树的值全部都大于根节点的值。

所以,当我们采用中序遍历就可以得到有=升序的序列。

void INORDER(Node* root)
{if (root == nullptr)return;INORDER(root->_left);cout << root->_val << " ";INORDER(root->_right);
}

在这里插入图片描述

二叉搜索树的查找

假设要寻找的值是key

牢记搜索二叉树的性质,从根节点开始向下寻找,
当key > 当前节点的时候,去右子树寻找即可
当key < 当前节点的时候,去左子树寻找即可
找到了就返回true,没找到就返回false

bool find(const DataType& key)
{Node* cur = _root;while (cur){if (key > cur->_val){cur = cur->_right;//大了就去右子树找}else if (key < cur->_val)//小了就去左子树找{cur = cur->_left;}else{return true;}}return false;
}

在这里插入图片描述

注意:思考搜索二叉树查找的时间复杂度
是不是很多同学认为是O(logN)?
实际上并不是,应该查找高度次,但是高度就是logN了吗?
事实上,存在极端情况,二叉树会退化成单边二叉树,此时树的高度就是n - 1,
此时,时间复杂度是O(N)。


搜索二叉树的插入

记要插入值key

要插入首先要找到该在何处插入。

显然,这里的思路和查找类似
当key大了,就往右子树走
当key小了,就往左子树走
直到走到空的位置,可以插入。

找到位置后,用key构建一个新的节点,链接到到搜索树上去即可。

那么这里就需要寻找父节点了,所以,我们需要引入一个parent指针来标记父亲节点。

但是?究竟是插在父亲节点的左子树还是右子树呢?
去和父节点的值进行比较即可。
大于父节点的值,插在右边,小于父节点的值插在左边。

对于插入,如果搜索二叉树里面已经存在了该key值,那么就不重复插入,所以搜索二叉树就有了去重的特性

bool insert(const DataType& key)
{if (_root == nullptr){_root = new Node(key);return true;}Node* cur = _root;Node* parent = nullptr;while (cur){if (key > cur->_val){parent = cur;cur = cur->_right;}else if (key < cur->_val){parent = cur;cur = cur->_left;}else{return false;//已经有了,就不重复插入}}

在这里插入图片描述

搜索二叉树的删除

搜索二叉树最难的部分就是删除,这里需要仔细体会

对于删除节点,我们会发现树里面有三种节点

  1. 当前节点没有子节点
  2. 当前节点只有一个子节点
  3. 当前节点有两个子节点

对于这三种情况我们都需要进行思考。

  1. 当前节点没有子节点
    此时我们只需要释放该节点,将父亲节点指向空即可
  2. 当前节点只有一个子节点
    a. 左子树为空
    将父亲节点指向右子树,释放当前节点即可
    b. 右子树为空
    将父亲节点指向左子树,释放当前节点即可
  3. 当前节点有两个子节点(最复杂的情况

    此时,我们就需要去找到一个合适的值,来替代当前节点。
    很明显,这个值一定要大于左子树,小于右子树
    那么,也就是,我们需要找到左子树的最大值,或者右子树的最小值来替代当前节点
    这里我们以寻找右子树的最小值为例。
    如何寻找右子树的最小值?
    右子树的最小值一定在右子树的最左边,否则就会有更小的值(这里读者理解不了的话,可以画个图理解一下)
    所以这里只需要设置一个指针rightMin,从cur->right开始一路向左,直到左子树为空停止。
    此时rightMin就是右子树的最小值。
    这是将rightMin的值给cur即可,然后删除rightMin节点
    这里删除非常简单,只需要让rightMin的父亲的左指向rightMin的右即可。(所以需要引入rightMinP指针记录rightMin的父亲)

算法实现过程中的一些细节:
(1)首先对于第三种情况,我们去寻找右子树的最小节点,就是寻找右子树的最左边,但是如果右子树没有左节点怎么办?
在这里插入图片描述
比如这里要删除8,右子树没有左节点,此时要进行特判,让cur的右指向rightMin的右。

(2)对于1,2两种情况,需要父亲节点指向子节点的左或者右
但是,对于根节点来说,根节点没有父亲,就会出现空指针问题。
在这里插入图片描述
对于10这个节点就没有父亲节点,
那么此时就需要将root 指向 cur的右
右子树为空类似。

bool erase(const DataType& key)
{if (_root == nullptr)return false;Node* cur = _root;Node* parent = nullptr;while (cur){if (key > cur->_val){parent = cur;cur = cur->_right;}else if (key < cur->_val){parent = cur;cur = cur->_left;}else{//找到了,开始删除if (cur->_left == nullptr){//左边为空if (parent == nullptr)//特判一下{_root = cur->_right;delete cur;return true;}if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr){//右边为空if (parent == nullptr){_root = cur->_left;delete cur;return true;}if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;return true;}else{//两个节点都为空Node* rightMin = cur->_right;Node* rightMinP = cur;//找右子树最小的节点while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}cur->_val = rightMin->_val;if (rightMin == rightMinP->_right){cur->_right = rightMin->_right;}else{rightMinP->_left = rightMin->_right;}delete rightMin;//这里不删curreturn true;}}}return false;//找不到返回false;}

在这里插入图片描述

搜索二叉树的应用

搜索二叉树分为k型和kv型,上述就是以k型为例,当然,kv型类似,聪明的读者肯定能举一反三。

1、k型
K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

上面的例子就是k型,就不举例子了。

2、kv型
KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:
比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;
再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。

void TestBSTree3()
{// 输入单词,查找单词对应的中文翻译BSTree<string, string> dict;dict.Insert("string", "字符串");dict.Insert("tree", "树");dict.Insert("left", "左边、剩余");dict.Insert("right", "右边");dict.Insert("sort", "排序");// 插入词库中所有单词string str;while (cin>>str){BSTreeNode<string, string>* ret = dict.Find(str);if (ret == nullptr){cout << "单词拼写错误,词库中没有这个单词:" <<str <<endl;}else{cout << str << "中文翻译:" << ret->_value << endl;}}
}

在这里插入图片描述


剩下的构造 ,析构,拷贝构造比较简单,这里就不讲解了。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

剑侠情缘c++源码全套(增加缺失的头文件和相关的库,其它网上流传的都是不全的)剑网三源码

剑侠情缘c源码全套&#xff08;增加缺失的头文件和相关的库&#xff0c;其它网上流传的都是不全的&#xff09; 下载地址&#xff1a; 通过网盘分享的文件&#xff1a;剑侠情缘c源码全套&#xff08;增加缺失的头文件和相关的库&#xff0c;其它网上流传的都是不全的&#xff0…

飞睿智能3公里WiFi实时图传模块,隧道高速无线传输抗干扰,实时不卡顿

在数字化快速发展的今天&#xff0c;无线通信技术日新月异&#xff0c;其中WiFi实时图传模块凭借其高效、稳定、便捷的传输特性&#xff0c;正逐渐在各个领域崭露头角。特别是当我们谈论到3公里WiFi实时图传模块时&#xff0c;这不仅是对传统无线传输技术的一次革新&#xff0c…

父子Shell你了解多少?一起解读吧

一.source和点、bash \sh 、./script区别 1.source和点&#xff0c;执行脚本&#xff0c;只在当前shell环境中执行生效 2.指定bash\sh 解释器运行脚本&#xff0c;是开启subshell&#xff0c;开启子shell运行脚本 命令 3. ./script,都会指定shebang,通过解释器运行&#xff0c;…

PAT甲级-1090 Highest Price in Supply Chain

题目 题目大意 一个供应链由供应商、经销商、零售商组成。供应商作为根节点&#xff0c;售卖价格为P的商品&#xff0c;每经过一级经销商或零售商都会以高于r%的价格批发或出售。题目给出总节点数n&#xff0c;每个节点的编号从0到n-1&#xff0c;给出的每个值是该节点编号的索…

臀部筋膜炎最佳治疗方法

臀部筋膜炎的最佳治疗方法因个体差异而异&#xff0c;但通常包括以下几个方面&#xff1a; 一、药物治疗 非甾体抗炎药&#xff1a;如布洛芬、双氯芬酸钠等&#xff0c;这些药物通过抑制前列腺素合成来减少炎症和疼痛&#xff0c;适用于缓解轻至中度的急性发作期臀部筋膜炎引…

跨平台数据库工具DataGrip v2024.2全新发布——增加智能刷新功能

DataGrip 是一个跨平台的数据库工具可在Windows&#xff0c;OS X 和 Linux上使用。同时支持多种数据库&#xff0c;包含了SQL Server&#xff0c;Oracle&#xff0c;PostgreSQL&#xff0c;MySQL&#xff0c;DB2&#xff0c;Sybase&#xff0c;SQLite&#xff0c;Derby&#xf…

智慧农业的引擎:高标准农田灌区信息化的探索与实践

在现代农业的广阔图景中&#xff0c;智慧农业作为一股革新力量&#xff0c;正逐步重塑着传统农业的面貌。其中&#xff0c;高标准农田灌区的信息化建设不仅是智慧农业的重要引擎&#xff0c;更是实现农业可持续发展、提高资源利用效率的关键路径。 高标准农田灌区信息化的内涵…

828华为云征文|华为云Flexus云服务器X实例 基于CentOS系统镜像快速部署Laravel开源论坛

最近公司可热闹了&#xff01;大家都在为搭建博客论坛系统忙得不可开交&#xff0c;尤其是在选服务器这件事儿上&#xff0c;那叫一个纠结。 同事 A 说&#xff1a;“咱得选个厉害的服务器&#xff0c;不然这论坛以后卡得跟蜗牛爬似的可咋办&#xff1f;” 同事 B 回应道&#…

C++11语法(基础)【一】

目录 1. C11简介 2. 统一的列表初始化 2.1 &#xff5b;&#xff5d;初始化 2.2 std::initializer_list 3. 声明 3.1 auto 3.2 decltype 3.3 nullptr 声明&#xff1a;C11我会分几篇来讲&#xff0c;每一篇我都会讲几种特性。 1. C11简介 在2003年C标准委员会曾经提交了一份技术…

slam入门学习笔记

SLAM是Simultaneous localization and mapping缩写&#xff0c;意为“同步定位与建图”&#xff0c;主要用于解决机器人在未知环境运动时的定位与地图构建问题&#xff0c;目前广泛用于机器人定位导航领域&#xff0c;VR/AR方面&#xff0c;无人机领域&#xff0c;无人驾驶领域…

【小白请绕道】Redis 的 I/O 多路复用技术,它是如何工作的?

Redis 的 I/O 多路复用技术是其高性能的关键之一。在单个线程中&#xff0c;Redis 可以同时处理多个网络连接&#xff0c;这是通过使用 I/O 多路复用技术实现的。这种技术允许 Redis 在单个线程中监听多个套接字&#xff0c;并在套接字准备好执行操作时&#xff08;如读取或写入…

STM32F1,F4,L1系列禁止JTAG和SW引脚方法

STM32F1系列 程序中在使用到JTAG、SWD的某个IO 时&#xff0c;需要禁用掉相关调试方法后&#xff0c;再配置相应的IO方式。在需要相应的接口配置前使用这些代码。 对于F1系列&#xff0c;调用函数进行专门的禁止。 标准库配置方式&#xff1a; RCC_APB2PeriphClockCmd(RCC_A…

2024源代码加密软件TOP10分享|企业源代码加密软件

在现代企业的数字化转型过程中&#xff0c;源代码作为企业核心知识产权之一&#xff0c;至关重要。为了防止数据泄漏、外部攻击以及内部违规操作&#xff0c;企业越来越关注源代码的加密和保护。本文将为大家介绍2024年最受欢迎的十大源代码加密软件&#xff0c;帮助企业更好地…

助力新能源汽车行业的发展,尽在AUTO TECH 2025华南展

随着全球对环境保护的重视和石油资源的逐渐减少&#xff0c;新能源汽车的发展已经成为必然趋势。预计未来几年&#xff0c;新能源汽车的市场规模和销量将继续保持快速增长。根据 IDC 预测&#xff0c;中国乘用车市场中新能源车市场规模将在 2028 年超过 2300 万辆&#xff0c;年…

面试经典 150 题:力扣88. 合并两个有序数组

每周一道算法题启动 题目 【题目链接】 【解法一】合并后排序 排序后的数组自动省略0的数字&#xff0c;又学到了 class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {//合并两个数组后排序for(int i0; i<…

基于springboot渔具销售系统设计与开发

文未可获取一份本项目的java源码和数据库参考。 选题背景及意义 随着社会的发展,渔具销售企业之间的竞争与合作变得越来越频繁.而销售部门作为企业的窗口,其地位无与伦比。在激烈的市场竞争中,企业要能对市场变化作出反应,销售部门起了关键作用,销售部门作为企业的生命已经成了…

什么味道呀!热播剧《凡人歌》启示:这几年,请主动给生活降级——早读(逆天打工人爬取热门微信文章解读)

试试就试试 引言Python 代码第一篇 洞见 热播剧《凡人歌》启示:这几年&#xff0c;请主动给生活降级第二篇 在错误的地方重复&#xff0c;毫无价值结尾 &#xff08;哈哈哈 真的吗&#xff1f;&#xff09; 引言 回复平静 啥啥都回复平静 家里人不要钱了 股票也跌停了 哈哈 怎…

搭建EMQX MQTT服务器并接入Home Assistant和.NET程序

本文主要介绍如何使用Docker搭建EMQX MQTT服务器&#xff0c;并将其接入到Home Assistant中&#xff0c;最后演示如何使用.NET接入MQTT。 1. 背景 在智能家居系统中&#xff0c;MQTT&#xff08;消息队列遥测传输协议&#xff09;是一种轻量级的消息传输协议&#xff0c;特别适…

leetcode-10. 正则表达式匹配

题目描述 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s 的&#xff0c;而不是部分字符串。 示例 1&#xff1a; 输入&a…

稀土阻燃剂应用在PE(聚乙烯)上的优势

稀土阻燃协效剂基于稀土4f电子层结构带来的特有属性,在聚合物材料燃烧时可催化酯化成炭,迅速在高分子表面形成致密连续的碳层,隔绝聚合物材料内部的可燃性气体与氧气的接触,从而达到阻燃抑烟的效果,且燃烧时不产生有毒有害气体。其主要特点如下&#xff1a; 有效性&#xff1a;…