当前位置: 首页 > news >正文

数据结构-考研难点代码突破(C++实现树型查找-二叉搜索树(二叉排序树))

文章目录

  • 1.二叉搜索树基本操作
    • 二叉搜索树的效率分析
  • 2. C++实现

1.二叉搜索树基本操作

二叉排序树是具有下列特性的二叉树:

  1. 若左子树非空,则左子树上所有结点的值均小于根结点的值。
  2. 若右子树非空,则右子树上所有结点的值均大于根结点的值。
  3. 左、右子树也分别是一棵二叉排序树

根据二叉排序树的定义,左子树结点值< 根结点值< 右子树结点值。
所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列。

二叉排序树的搜索

  1. 从根结点开始,沿某个分支逐层向下比较的过程。
  2. 若二叉排序树非空,先将给定值与根结点的关键字比较,若相等,则查找成功
  3. 若不等,如果小于根结点的关键字,则在根结点的左子树上查找,否则在根结点的右子树上查找。

这个过程可以通过递归或者非递归实现实现

二叉排序树的插入

  1. 若原二叉排序树为空,则直接插入结点
  2. 若关键字k小于根结点值,则插入到左子树,若关键字k大于根结点值,则插入到右子树。

插入的结点一定是一个新添加的叶结点,且是查找失败时的查找路径上访问的最后一个结点的左孩子或右孩子.

二叉排序树的删除

在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须先把被删除结点从存储二叉排序树的链表上摘下,将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。删除操作的实现过程按3种情况来处理

  1. 若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质

  2. 若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置

  3. 若结点z有左、右两棵子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况。可以使用递归解决这个问题。

    直接后继:节点右子树中最左节点(右子树最小节点)

    删除流程图:具体看代码流程
    在这里插入图片描述

二叉搜索树的效率分析

二叉排序树的查找效率,主要取决于树的高度。

  1. 若二叉排序树的左、右子树的高度之差的绝对值不超过1(这样的二叉排序树称为平衡二叉树)它的平均查找长度为O(logN)

  2. 若二叉排序树是一个只有右(左)孩子的单支树(类似于有序的单链表),则其平均查找长度为O(N)

在这里插入图片描述
a图的平均搜索成功长度ASL:类似折半查找(1x1 + 2x2+……h×2h-1) )(每层的节点不一定放满,需要针对题目灵活处理)
(1×1+2×2+3×4+4×3)÷10=2.9

b图的平均搜索成功长度ASL:(1+10)/2=5.5
因为此时搜索二叉树由树型退化为线型,平均搜索长度为(n+1)/2

二叉排序树与二分查找相似。就平均时间性能而言,二叉排序树上的查找和二分查找差不多。

但二分查找的判定树唯一,而二叉排序树的查找不唯一,相同的关键字其插入顺序不同可能生成不同的二叉排序树。

二叉排序树与二分搜索:

  1. 二叉排序树无须移动结点,只需修改指针即可完成插入和删除操作, 平均执行时间为O(logN)
  2. 二分查找的对象是有序顺序表,若有插入和删除结点的操作,所花的代价是O(n)。
  3. 当有序表是静态查找表时,宜用顺序表作为其存储结构,采用二分查找实现其查找操作;若有序表是动态查找表,则应选择二叉排序树作为其逻辑结构.

2. C++实现

// 二叉搜索树头文件实现
#include <iostream>
#include <vector>
#include <algorithm>struct TreeNode
{int _val;TreeNode *_left;TreeNode *_right;TreeNode(int val) : _val(val), _left(nullptr), _right(nullptr) {}
};class SearchTree
{
private:TreeNode *root = nullptr;/*** @brief 在二叉搜索树中查找节点值为val的节点** @param val 查找节点的值* @param node 如果找到了这个节点,node就是这个节点的地址,否则为null* @param part part这个节点的父亲,如果这个节点为null,这个参数输出null*/void _find(int val, TreeNode *&node, TreeNode *&part){TreeNode *ptr = root;TreeNode *prev = nullptr;while (ptr != nullptr){if (ptr->_val == val){node = ptr;break;}else if (ptr->_val > val){prev = ptr;ptr = ptr->_left;}else{prev = ptr;ptr = ptr->_right;}}node = ptr;part = prev;}bool _erase(int val, TreeNode *&node){if (node == nullptr){return false;}else{if (node->_val > val){_erase(val, node->_left);}else if (node->_val < val){_erase(val, node->_right);}else{if (node->_left == nullptr){TreeNode *del = node;node = node->_right;delete del;}else if (node->_right == nullptr){TreeNode *del = node;node = node->_left;delete del;}else{// 找要删除节点的后继TreeNode *right_min_node = node->_right;while (right_min_node->_left != nullptr){right_min_node = right_min_node->_left;}// 记录right_min_node这个节点的值,吧这个节点的值和node节点交换,在删除right_min_node这个节点即可// right_min_node这个节点的左子树一定为空,在上面顶点流程会处理int tmp = right_min_node->_val;_erase(tmp, node->_right);node->_val = tmp;}}return true;}}// 判断一棵树是否是二叉搜索树,检查每个节点是否满足节点值的取值范围bool _isSearchTree(TreeNode *node, int min, int max){if (node == nullptr)return true;if (node->_val < min || node->_val > max){return false;}return _isSearchTree(node->_left, min, node->_val - 1) && _isSearchTree(node->_right, node->_val + 1, max);}void _display_inorder(TreeNode *node){if (node == nullptr)return;_display_inorder(node->_left);std::cout << node->_val << " ";_display_inorder(node->_right);}int _max(){TreeNode *node = root;while (node->_right != nullptr){node = node->_right;}return node->_val;}int _min(){TreeNode *node = root;while (node->_left != nullptr){node = node->_left;}return node->_val;}public:SearchTree() = default;SearchTree(const std::vector<int> &buff){for (int i = 0; i < buff.size(); i++){insert(buff[i]);}}// 不允许重复插入相同的值bool insert(int val){if (root == nullptr){root = new TreeNode(val);return true;}else{TreeNode *pos = nullptr;TreeNode *prev = nullptr;_find(val, pos, prev);if (pos != nullptr){// 之前插入过,值重复return false;}else{// pos==nullptr;if (prev->_val > val){prev->_left = new TreeNode(val);}else{prev->_right = new TreeNode(val);}return true;}}}// 查找节点值为val的节点bool find(int val){TreeNode *node;TreeNode *part;_find(val, node, part);return node != nullptr;}// 删除搜索二叉树节点bool erase(int val){return _erase(val, root);}// 判断这颗树是否为二叉搜索树bool isSearchTree(){return _isSearchTree(root, _min(), _max());}// 中序遍历二叉搜索树void inorder(){_display_inorder(root);std::cout << "\n";}
};

测试代码:

#include "SearchTree.h"
#include <time.h>using namespace std;#define TIMES 10int main(int argc, char const *argv[])
{srand((unsigned int)time(0));// vector<int> ret = {1, 2, 3};vector<int> ret;for (int i = 0; i < TIMES; i++){ret.push_back(rand() % 100);}SearchTree tree(ret);tree.inorder();tree.insert(40);tree.inorder();cout << tree.isSearchTree() << endl;tree.insert(1);tree.erase(40);tree.inorder();cout << tree.isSearchTree() << endl;return 0;
}

在这里插入图片描述

相关文章:

数据结构-考研难点代码突破(C++实现树型查找-二叉搜索树(二叉排序树))

文章目录1.二叉搜索树基本操作二叉搜索树的效率分析2. C实现1.二叉搜索树基本操作 二叉排序树是具有下列特性的二叉树&#xff1a; 若左子树非空&#xff0c;则左子树上所有结点的值均小于根结点的值。若右子树非空&#xff0c;则右子树上所有结点的值均大于根结点的值。左、…...

emqx异常处理

启动异常 通过解压tar压缩包安装后通过 ./bin/emqx start 启动报错 WARNING: Default (insecure) Erlang cookie is in use. WARNING: Configure node.cookie in /opt/emqx/etc/emqx.conf or override from environment variable EMQX_NODE__COOKIE NOTE: Use the same config…...

Web前端:开始学习ReactJS需要知道什么?

毫无疑问&#xff0c;ReactJS是前端开发者中最著名的库之一&#xff0c;它的受欢迎程度与日俱增。用ReactJS构建的网站看起来非常棒&#xff0c;大多数开发新手都被它吸引住了。然而&#xff0c;许多新人和有经验的开发人员在没有首先了解先决条件的情况下&#xff0c;就直接用…...

卡诺图化简

1.相关概念 最小项&#xff1a;函数的某个乘积项包含了函数的全部变量&#xff08;原变量或反变量的形式&#xff09;&#xff0c;且每个变量仅出现一次&#xff0c;则这个乘积项为该函数的一个标准积项。 最小项中的原变量记为1&#xff0c;反变量记为0&#xff0c;当变量顺序…...

带你了解软件测试是做什么的

软件测试是互联网技术中一门重要的学科&#xff0c;它是软件生命周期中不可或缺的一个环节&#xff0c;担负着把控、监督软件的质量的重任。 人才稀缺&#xff0c;对于求职者来说就意味着机会。但是很多想学习软件测试的人对这个学科并不了解&#xff0c;也不知道该如何学习&a…...

企业电子招投标采购系统源码之功能模块功能描述

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…...

职场中的高手,是如何高质量解决问题?

职场总会遇见很多新问题&#xff0c;高手会从容应对&#xff0c;因为他们学习了一套通 用理论&#xff0c;可以处理工作当中的大部分内容&#xff0c;剩下的一部分能够用快速 提问的方式找到思路。 记得几年前有个同事 A&#xff0c;下午四点多项目突然丢过来一个活&#xff0c…...

报表生成工具Stimulsoft中的电子签名和 PDF 数字签名

Stimulsoft Reports 是一款报告编写器&#xff0c;主要用于在桌面和Web上从头开始创建任何复杂的报告。可以在大多数平台上轻松实现部署&#xff0c;如ASP.NET, WinForms, .NET Core, JavaScript, WPF, Angular, Blazor, PHP, Java等&#xff0c;在你的应用程序中嵌入报告设计器…...

【Hello Linux】Linux环境下写的第一个程序 -- 进度条

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;写出Linux中的第一个小程序 进度条 进度条小程序行缓冲区概念\r 和 \n进度条代码和演示行缓冲区概念 我们首先用两段代码来感受下行缓…...

【基础】性能测试,从0到实战(手把手教,非常实用)

一、性能基础 什么是性能测试--->本质? 基于协议来模拟用户发送的请求&#xff08;业务模拟&#xff09;&#xff0c;对服务器形成一定负载。关注点&#xff1a;时间性能、空间性能与界面无关 性能测试分类 性能测试&#xff08;狭义&#xff09; 性能测试方法是通过模…...

07-Java异常分类以及处理机制

1.异常概念 Java标准库内建了一些通用的异常&#xff0c;这些类以Throwable为顶层父类。Throwable又派生出Error类和Exception类。 1.错误&#xff1a;是程序无法处理的错误&#xff0c;表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关&#xff0c;而表示…...

用到的C++的相关知识-----未完待续

文章目录前言一、vector函数的使用1.1 构造向量二、常用函数2.1 矩阵输出函数2.2 向量输出函数2.3 矩阵的使用2.4三、new的用法3.1 内存的四种分区3.2 new的作用3.33.4四、4.14.24.34.4总结前言 只是为方便学习&#xff0c;不做其他用途 一、vector函数的使用 有关的文章 C v…...

JavaScript刷LeetCode拿offer-贪心算法

前言 学习算法的时候&#xff0c;总会有一些让人生畏的名词&#xff0c;比方动态规划&#xff0c;贪心算法 等&#xff0c;听着就很难&#xff1b;而这一 part 就是为了攻破之前一直没有系统学习的 贪心算法&#xff1b; 有一说一&#xff0c;做了这些贪心题&#xff0c;其实…...

selenium

下载并安装selenium 安装&#xff1a;cmd中执行 pip install -i https://pypi.douban.com/simple selenium执行完成后 pip show selenium 可查看安装是否成功安装浏览器驱动&#xff0c;查看当前浏览器的版本选择合适的驱动并下载 chrome的链接&#xff1a;https://chromedrive…...

SpringMVC的视图

转发视图ThymeleafView若使用的视图技术为Thymeleaf&#xff0c;在SpringMVC的配置文件中配置了Thymeleaf的视图解析器&#xff0c;由此视图解析器解析之后所得到的是ThymeleafView。解析&#xff1a;当控制器方法中所设置的视图名称没有任何前缀时&#xff0c;此时的视图名称会…...

idea使用本地代码远程调试线上运行代码---windows环境

场景&#xff1a; 今天在书上看了一个代码远程调试的方法&#xff0c;自己本地验证了一下感觉十分不错&#xff01;&#xff01; windows环境&#xff1a; 启动测试jar包&#xff1a;platform-multiappcenter-base-app-1.0.0-SNAPSHOT.jar 测试工具&#xff1a;postman,idea 应…...

简单记录简单记录

目录1.注册Gmail2.注册ChatGPT3.验证“真人”使用4.开始使用1.注册Gmail 第一步先注册一个谷歌邮箱&#xff0c;你也可以使用微软账号&#xff0c;大部分人选择使用gmail。 申请谷歌邮箱 选择个人用途创建账号即可。 &#x1f4cc;温馨提示&#xff1a; 你直接使用guo内的网…...

源码系列 之 ThreadLocal

简介 ThreadLocal的作用是做数据隔离&#xff0c;存储的变量只属于当前线程&#xff0c;相当于当前线程的局部变量&#xff0c;多线程环境下&#xff0c;不会被别的线程访问与修改。常用于存储线程私有成员变量、上下文&#xff0c;和用于同一线程&#xff0c;不同层级方法间传…...

C语言入门(1)——特点及关键字

1、C特点及与Java区别 1.1、C特点 面向过程 一般用于嵌入式开发、编写最底层的程序、操作系统 可以直接操作内存 可以封装动态库 不容易跨平台 有指针 可以直接操作串口 线程更加灵活 和硬件打交道速度是最快的 1.2、和Java区别 C是C的增强版&#xff0c;增加了一些新的特性&…...

react中useEffect和useLayoutEffect的区别

布局上 useEffect在浏览器渲染完成后执行useLayoutEffect在DOM更新后执行 特点 useLayoutEffect 总是比 useEffect 先执行&#xff1b;useLayoutEffect与componentDidMount、componentDidUpdate调用时机相同&#xff0c;都是在DOM更新后&#xff0c;页面渲染前调用&#xff1…...

从零部署私有化AI对话框架:igogpt架构解析与实战指南

1. 项目概述与核心价值最近在折腾AI应用部署的朋友&#xff0c;可能都听说过一个词叫“套壳ChatGPT”。这类项目通常是把OpenAI的API接口包装一下&#xff0c;做个Web界面&#xff0c;让用户能更方便地使用。但今天要聊的这个项目——igolaizola/igogpt&#xff0c;它给我的感觉…...

TTS听觉校对法:技术写作质量提升的工程实践指南

1. 为什么我们需要“听”自己的文字&#xff1a;一个被忽视的校对革命作为一名写了十几年技术文档和博客的老兵&#xff0c;我敢说&#xff0c;最让我头疼的不是构思&#xff0c;也不是码字&#xff0c;而是最后那一步——校对。你肯定也经历过&#xff1a;一封精心撰写的邮件发…...

AI时代DevSecOps脚手架:5分钟构建安全合规的React+Supabase应用

1. 项目概述&#xff1a;一个为AI编码时代量身定制的DevSecOps启动器 如果你和我一样&#xff0c;经常用 Cursor、Lovable 这类 AI 编程工具快速构建应用原型&#xff0c;那你肯定遇到过这个痛点&#xff1a;项目跑起来了&#xff0c;功能也实现了&#xff0c;但当你准备把它变…...

【面试篇】ConcurrentHashMap 1.7与1.8:从分段锁到CAS+synchronized的演进之路

1. 从分段锁到CASsynchronized的演进背景 在Java并发编程中&#xff0c;HashMap是线程不安全的典型代表。当多个线程同时操作HashMap时&#xff0c;可能会出现数据丢失、环形链表等问题。为了解决这个问题&#xff0c;早期我们通常使用以下两种方式&#xff1a; HashTable&am…...

混合量子计算:qumode与qubit协同架构解析

1. 混合量子计算基础概念解析 量子计算领域正在经历一场静默的革命——连续变量(qumode)与离散变量(qubit)的混合架构正突破传统计算范式的边界。这种混合架构不是简单的技术叠加&#xff0c;而是通过量子态的精妙耦合&#xff0c;在信息容量与计算稳定性之间建立起全新的平衡点…...

FPGA加速中性原子量子计算机的原子检测技术

1. 中性原子量子计算机的原子检测挑战量子计算领域近年来最激动人心的进展之一&#xff0c;就是中性原子量子计算机的快速发展。这种量子计算机利用激光镊子&#xff08;光学镊子&#xff09;阵列来捕获和排列中性原子&#xff08;如铷、铯等碱金属原子&#xff09;&#xff0c…...

CANN/asc-devkit ReduceProd API文档

ReduceProd 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言&#xff0c;原生支持C和C标准规范&#xff0c;主要由类库和语言扩展层构成&#xff0c;提供多层级API&#xff0c;满足多维场景算子开发诉求。 项目地址: https://gitcode.com…...

视频技术演进:从模拟到数字的革命与压缩技术解析

1. 视频技术演进&#xff1a;从模拟到数字的革命上世纪30年代末&#xff0c;当第一套视频标准在美国诞生时&#xff0c;谁也没想到这个被称为RS-170的技术会成为现代视频技术的基石。作为最早的模拟视频标准&#xff0c;RS-170定义了525线&#xff08;其中480线为有效视频内容&…...

AI代理规则引擎:构建安全可控的智能体管控系统

1. 项目概述&#xff1a;当AI代理需要“交通规则”最近在折腾AI代理&#xff08;Agent&#xff09;的开发&#xff0c;发现一个挺有意思但又普遍头疼的问题&#xff1a;你给一个代理下达指令&#xff0c;比如“帮我分析一下这个季度的销售数据”&#xff0c;理论上它应该能调用…...

企业团队如何利用Taotoken统一管理API密钥与下载用量报告

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 企业团队如何利用Taotoken统一管理API密钥与下载用量报告 在团队协作开发与使用大模型API的过程中&#xff0c;如何安全、高效地管…...