二叉搜索树的实现[C++]

文章目录

  • 搜索二叉树
    • 概念
    • 二叉搜索树的功能
      • 查找
  • 实现搜索二叉树
    • 节点的定义
    • 建立搜索二叉树
    • 接口
      • 插入
      • 搜索
      • 打印
      • 删除
  • 总结

今天本堂主来一起讨论下什么是搜索二叉树,和如何实现二叉搜索树

搜索二叉树

那么二叉搜索树似乎如何实现搜索呢?二叉搜索树和普通二叉树有什么不同呢?

概念

搜索二叉树又可以称作二叉搜索树或二叉排序树。
搜索二叉树需要满足几个条件或者说要具备几个性质:

  • 1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 3.它的左右子树也分别为二叉搜索树
    在这里插入图片描述

二叉搜索树的功能

查找

二叉搜索树的查找:

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

这样在理想情况下时间复杂度是O(logn),而极端情况如下图时间复杂度还是O(n²)

在这里插入图片描述

实现搜索二叉树

那么如何实现搜索二叉树呢?
在这里插入图片描述
咱们可以按照这个思路去实现

节点的定义

定义节点的时候二叉树包括:本身值,左节点,右节点
那么我们就可以这样来定义节点

template<class K>
struct BSTNode
{K _key;BSTNode<K>* _left;BSTNode<K>* _right;BSTNode(const K& key):_key(key),_left(nullptr),_right(nullptr){}
};

这样我们就定义了一个二叉搜索树的节点结构体,构造函数则是用于创建节点并初始化建值,左右指针默认为空

建立搜索二叉树

那么接下来我们就进行声明根节点和初始化根节点为我们后面实现搜索二叉树的功能做铺垫

template<class K>
class BSTree
{typedef BSTNode<K> Node;\*...*\
private:Node* _root = nullptr;
};

声明根节点:我们声明了一个名为 _root 的指针,该指针指向 Node 类型的对象。这里的 Node 是 BSTNode 的类型别名。

初始化根节点:通过将 _root 初始化为 nullptr,我们是在创建一个空的搜索二叉树,为后面做铺垫。

接口

万事俱备那么我们就来实现搜索二叉树的功能吧

插入

首先一定是向空的搜索二叉树中插入数。

很简单我们先在BSTree的类里面定义一个Insert的函数

//插入bool Insert(const K& key){if (_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;}else{return false;}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else if (parent->_key > key){parent->_left = cur;}return true;}
  • 我们先判断_root如果为空那么我们定义一个新新节点连接到根节点,并给新节点赋值
  • 其次如果树不为空,遍历树来找到正确的插入位置(我这里用的双指针防止迷路)
  • 如果找到和键值相同的节点则不插入
  • 符合搜索二叉树的性质加入新节点

搜索

有了插入的铺垫我们搜索的函数在遍历查找树这里就可以CV下

//查找bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key == key){return true;}else if (cur->_key < key){cur = cur->_right;}else{cur = cur->_left;}}return false;}

不同的是在插入的时候找到和键值相同的值是返回false 而在搜索函数找到键值返回true证明找到了,而没找到值的时候才返回false

打印

那么打印这里就正常写就可以,但是会有一点点小问题
在我正常写打印函数之后,因为_root是私有的只有内部能用所以我用不了

	void InOrder(){if (root == nullptr){return;}InOrder(root->_left);cout << root->_key << " ";InOrder(root->_right);}

在这里我就进行了些调整

	//打印void InOrder(){_InOrder(_root);cout << endl;}
private://打印的子函数void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}

这样我用个子函数之后再在打印函数中调用子函数就可以了

删除

相较前两个删除是比较麻烦的

看长度可知⬇

	//删除bool Erase(const K& key){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;}//删除else{//0-1个孩子if (cur->_left == nullptr){if (parent == nullptr){_root = cur->_right;}else{if (parent->_left == cur){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;return true;}else if (cur->_right == nullptr){if (parent == nullptr){_root = cur->_left;}else{if (parent->_left == cur){parent->_left == cur->_left;}else{parent->_right = cur->_left;}}delete cur;return true;}//两个孩子else{Node* rightMinP = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}cur->_key = rightMin->_key;if (rightMinP->_left == rightMin){rightMinP->_left = rightMin->_right;}else{rightMinP->_right = rightMin->_right;}delete rightMin;return true;}}}return false;}

那么删除这里我在 BSTree 类中定义成员函数 Erase,用于删除搜索二叉树中具有特定键值 key 的节点。

  1. 定义函数bool Erase(const K& key),这是一个返回 bool 类型的函数,它接受一个键值 key 作为参数。
  2. 查找要删除的节点
    • 初始化两个指针 parentcur,分别用于跟踪父节点和当前节点。
    • 进入一个循环,直到找到要删除的节点或者当前节点为 nullptr
    • 在循环中,通过比较 cur->_keykey 来确定是否继续向左或向右遍历。
  3. 删除节点的逻辑
    • 如果找到要删除的节点,则根据节点是否有子节点或子节点的数量来决定如何删除节点。
    • 如果节点只有一个子节点(要么是左子节点,要么是右子节点),则直接将父节点的相应指针指向该子节点。
    • 如果节点有两个子节点,则需要找到右子树中的最小节点(即右子树的最左下角的节点),将其值复制到当前节点,然后删除右子树中的最小节点。
  4. 释放内存
    • 在删除节点后,如果节点不再被引用,则释放其内存。
  5. 返回结果
    • 如果成功删除节点,返回 true
    • 如果循环结束而没有找到要删除的节点,返回 false
      这段代码实现了搜索二叉树中键值的删除操作,它通过递归或迭代的方式找到要删除的节点,并确保在删除节点后树仍然保持搜索二叉树的性质。

总结

那么以上就是搜索二叉树的说明和实现,能给我点点赞吗?

完整代码:

#pragma once
#include <iostream>
using namespace std;template<class K>
struct BSTNode
{K _key;BSTNode<K>* _left;BSTNode<K>* _right;BSTNode(const K& key):_key(key),_left(nullptr),_right(nullptr){}
};template<class K>
class BSTree
{typedef BSTNode<K> Node;
public://插入bool Insert(const K& key){if (_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;}else{return false;}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else if (parent->_key > key){parent->_left = cur;}return true;}//查找bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key == key){return true;}else if (cur->_key < key){cur = cur->_right;}else{cur = cur->_left;}}return false;}//删除bool Erase(const K& key){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;}//删除else{//0-1个孩子if (cur->_left == nullptr){if (parent == nullptr){_root = cur->_right;}else{if (parent->_left == cur){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;return true;}else if (cur->_right == nullptr){if (parent == nullptr){_root = cur->_left;}else{if (parent->_left == cur){parent->_left == cur->_left;}else{parent->_right = cur->_left;}}delete cur;return true;}//两个孩子else{//右子树的最大节点作为替代节点/*Node* rightMinP = nullptr;Node* rightMin = cur->_right;while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}cur->_key = rightMin->_key;rightMinP->_left = rightMinP->_right;delete rightMin;return true;*/Node* rightMinP = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}cur->_key = rightMin->_key;if (rightMinP->_left == rightMin){rightMinP->_left = rightMin->_right;}else{rightMinP->_right = rightMin->_right;}delete rightMin;return true;}}}return false;}//打印void InOrder(){_InOrder(_root);cout << endl;}
private://打印的子函数void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}private:Node* _root = nullptr;
};

封面图
在这里插入图片描述

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

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

相关文章

linux 之时间子系统(八):hrtime 的实现机制

一、hrtimer 概述 在Linux内核中已经存在了一个管理定时器的通用框架。不过它也有很多不足&#xff0c;最大的问题是其精度不是很高。哪怕底层的定时事件设备精度再高&#xff0c;定时器层的分辨率只能达到Tick级别&#xff0c;按照内核配置选项的不同&#xff0c;在100Hz到10…

数据库管理1

数据库管理 数据库运维。 sql语句 数据库用来增删改查的语句 备份 数据库的数据进行备份 主从复制&#xff0c;读写分离&#xff0c;高可用。 数据库的概念和相关的语法和规范&#xff1a; 数据库&#xff1a;组织&#xff0c;存储&#xff0c;管理数据的仓库。 数据库的管理系…

一篇文章让你掌握计算网络的HTTP协议!!

HTTP 浏览器的服务原理http协议webTCP/IP协议族TCP/IP协议族分层应用层传输层网络层链路层数据包的封装过程HTTP数据传输过程传输层——TCP三次握手第一次握手第二次握手第三次握手三次握手的目的DNS域名解析HTTP完整事务处理过程HTTP协议的特点支持客户/服务器模式简短快速灵活…

钡铼Modbus TCP耦合器BL200实现现场设备与SCADA无缝对接

前言 深圳钡铼技术推出的Modbus TCP耦合器为SCADA系统与现场设备之间的连接提供了强大而灵活的解决方案&#xff0c;它不仅简化了设备接入的过程&#xff0c;还提升了数据传输的效率和可靠性&#xff0c;是工业自动化项目中不可或缺的关键设备。本文将从Modbus TC、SCADA的简要…

Apache网页优化(企业网站结构部署与优化)

本章结构 一、Apache网页优化 在使用 Apache 作为 Web 服务器的过程中&#xff0c;只有对 Apache 服务器进行适当的优化配置&#xff0c;才能让 Apache 发挥出更好的性能。反过来说&#xff0c;如果 Apache 的配置非常糟糕&#xff0c;Apache可能无法正常为我们服务。因此&…

Java8的新特性

Java8的新特性 一、函数式接口1、Java内置的函数式接口 二、Lambda表达式1、Lambda作用2、语法3、Lambda表达式的六种使用3.1、抽象方法&#xff1a;无参、无返回值3.2、抽象方法&#xff1a;需要传一个参数、无返回值3.3、抽象方法&#xff1a;需要传一个参数&#xff08;类型…

【iOS】OC类与对象的本质分析

目录 前言clang常用命令对象本质探索属性的本质对象的内存大小isa 指针探究 前言 OC 代码的底层实现都是 C/C代码&#xff0c;OC 的对象都是基于 C/C 的数据结构实现的&#xff0c;实际 OC 对象的本质就是结构体&#xff0c;那到底是一个怎样的结构体呢&#xff1f; clang常用…

IDEA实现SpringBoot项目的自打包自发布自部署

目录 前言 正文 操作背景 自发布 自部署 尾声 &#x1f52d; Hi,I’m Pleasure1234&#x1f331; I’m currently learning Vue.js,SpringBoot,Computer Security and so on.&#x1f46f; I’m studying in University of Nottingham Ningbo China&#x1f4eb; You can reach…

qt 创建一个左侧边线拖拽的矩形

1.概要 2.代码 2.1 代码第一版 在Qt中&#xff0c;要创建一个可以向左侧拖拽边线的矩形&#xff0c;你需要自定义一个QGraphicsRectItem的子类&#xff0c;并重写其事件处理函数来响应鼠标的拖拽动作。以下是一个简单的实现示例&#xff1a; #include <QApplication>…

设计模式——装饰者模式

设计模式——装饰者模式 1.问题1.1 方案一1.2 方案二 2.装饰者模式2.1 基本介绍2.2 结构2.3 代码实现 3.小结 1.问题 咖啡订单项目&#xff1a; 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)调料:Milk、Soy(豆浆)、Chocolat…

GB35114控制信令认证流程

GB35114控制信令认证说明&#xff1a; 注册成功后,信令发送方与信令接收方进行交互时,采用基于带密钥的杂凑方式保障信令来源安 全&#xff61;对除REGISTER消息以外的消息做带密钥的杂凑&#xff61;启用Date字段,扩展信令消息头域,在头域中 增加 Note 字 段 (值 为 Digest…

项目经理到底要不要考PMP?

在接待PMP学员中我惊讶地发现&#xff0c;不仅是项目经理&#xff0c;连开发、测试、产品、运营、销售、甚至财务团队的朋友们也都在积极备考。他们考证的原因主要有这几点&#xff1a; 1&#xff0c;职业发展&#xff1a;希望在职业生涯中晋升或转型到项目管理角色的朋友来说…

Spring MVC 全注解开发

1. Spring MVC 全注解开发 文章目录 1. Spring MVC 全注解开发2. web.xml 文件 的替代2.1 Servlet3.0新特性2.2 编写 WebAppInitializer 3. Spring MVC的配置3.1 Spring MVC的配置&#xff1a;开启注解驱动3.2 Spring MVC的配置&#xff1a;视图解析器3.3 Spring MVC的配置&…

SourceTree rebase(变基)的使用

参考资料 【Sourcetree】コミットを一つにまとめる【Sourcetree】リベースする 目录 前提0.1 merge与rebase0.2 merge合并分支0.3 rebase合并分支0.4 &#x1f4a5;超级注意事项&#x1f4a5; 一. 代码已提交&#xff0c;未推送&#xff0c;交互式变基1.1 通过SourceTree操作1…

【NLP实战】基于TextCNN的新闻文本分类

TextCNN文本分类在pytorch中的实现 基于TextCNN和transformers.BertTokenizer的新闻文本分类实现&#xff0c;包括训练、预测、数据加载和准确率评估。 目录 项目代码TextCNN网络结构相关模型仓库准备工作项目调参预测与评估 1.项目代码 https://github.com/NeoTse0622/Te…

怎么选流量套餐最划算呢,这篇文章建议收藏!

据小编了解&#xff0c;现在大多数用户手上都不止一张SIM卡&#xff0c;大部分都是双卡&#xff0c;甚至三卡了&#xff0c;那么&#xff0c;这些卡槽你真的利用对了吗&#xff1f; 这篇文章就告诉大家&#xff0c;如何更好的利用这两个卡槽&#xff0c;让你即省钱&#xff0c…

(02)Unity使用在线AI大模型(调用Python)

目录 一、概要 二、改造Python代码 三、制作Unity场景 一、概要 查看本文需完成&#xff08;01&#xff09;Unity使用在线AI大模型&#xff08;使用百度千帆服务&#xff09;的阅读和实操&#xff0c;本文档接入指南的基础上使用Unity C#调用百度千帆大模型&#xff0c;需要…

十五、C++11常用新特性—Lambda表达式

1.基本 这个好像是很好用的&#xff0c;其有以下有点&#xff1a; 声明式的编程风格&#xff1a;直接匿名定义目标函数或函数对象&#xff0c;不需要额外写一个命名函数或函数对象。简洁&#xff1a;避免了代码膨胀和功能分散&#xff0c;让开发更加高效。在需要的时间和地点…

Sentieon应用教程 | 唯一分子标识符(UMI)

介绍 本文介绍了使用Sentieon工具处理下一代测序数据的方法&#xff0c;同时利用分子条码信息&#xff08;也称为唯一分子索引或UMI&#xff09;。分子条码可以在测序之前在模板DNA分子的末端引入唯一标签&#xff0c;从而大大减少PCR重复和测序错误对变异调用过程的影响。 S…