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

C++:二叉搜索树的原理和模拟实现

文章目录

  • 二叉搜索树
    • 二叉搜索树的基本实现原理
  • 二叉搜索树的实现
    • 非递归版本的实现
    • 递归版本的实现

二叉搜索树

二叉搜索树也叫做二叉排序树,可以是空树,也可以是满足一些要求的二叉树

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

对于一种数据结构来说,大概率是实现增删查改这四个基本功能,这里实现的是增删查,对于改不实现的原因后续解释:

二叉搜索树的基本实现原理

1. 二叉搜索树的查找
a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找
b、最多查找高度次,走到到空,还没找到,这个值不存在

2. 二叉搜索树的插入
插入的具体过程如下:
a. 树为空,则直接新增节点,赋值给root指针
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

3. 二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点

对于这些情况,有下面的解决方案:
情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题–替换法删除

二叉搜索树的实现

二叉树中节点是最基本的信息,因此先进行节点的定义

template <class K>
struct Node
{Node(int key = 0):_left(nullptr), _right(nullptr), _key(key){}Node* _left;Node* _right;K _key;
};

非递归版本的实现

1. 插入

对于二叉搜索树来说,插入的逻辑是很简单的,如果插入的元素比目前的节点要大,就插入到右边,如果比目前的节点小,就插入到左边:

	bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);}else{Node* cur = _root;Node* parent = cur;while (cur){parent = cur;if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return false;}}if (parent->_key > key){parent->_left = new Node(key);}else{parent->_right = new Node(key);}}return true;}

2. 删除

二叉搜索树的删除较为复杂,下面分几种情况来进行讨论:

  1. 左根或右根为空

在这里插入图片描述
由于这种情况下最多只有一边有值,因此直接删除这个节点即可,令这个节点的父亲节点指向它的下一个节点

  1. 如果两边都有分支

解决的方法是,从要删除的这个节点的右子树中寻找一个可以替换它位置的数,这个数在寻找的时候选取的是右子树中的最小值,也就是右子树中的最左边的值就是所需要的值,交换后依旧可以满足二叉搜索树的条件,因此可以这样选择

	bool Erase(const K& key){Node* cur = _root;Node* parent = cur;while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr){// 左为空if (cur == _root){_root = cur->_right;}else{if (key < parent->_key){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr){// 右为空if (cur == _root){_root = cur->_left;}else{if (key < parent->_key){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else{// 左右都不为空parent = cur;Node* subleft = cur->_right;while (subleft->_left){parent = subleft;subleft = subleft->_left;}swap(cur->_key, subleft->_key);if (subleft == parent->_left){parent->_left = subleft->_right;}else{parent->_right = subleft->_right;}}return true;}}return false;}

3. 查找

有了前面的基础,查找的原理就很简单了,如果要找的值比当前值小,就到左树中寻找,如果要找的值比当前值大,就到右树中寻找,直到最后找到这个值为止,否则返回找不到

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

递归版本的实现

	bool InsertR(const K& key){return _Insert(_root, key);}bool EraseR(const K& key){return _Erase(_root, key);}bool FindR(const K& key){return _Find(_root, key);}void InOrder(){_InOrder(_root);cout << endl;}
private:bool _Insert(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (key > root->_key){_Insert(root->_right, key);}else if(key<root->_key){_Insert(root->_left, key);}return false;}bool _Erase(Node*& root, const K& key){if (root==nullptr){return false;}if (key < root->_key){_Erase(root->_left, key);}else if (key > root->_key){_Erase(root->_right, key);}else{if (root->_left == nullptr){Node* del = root;root = root->_right;delete del;return true;}else if (root->_right == nullptr){Node* del = root;root = root->_left;delete del;return true;}else{Node* subleft = root->_right;while (subleft->_left){subleft = subleft->_left;}swap(root->_key, subleft->_key);return _Erase(root->_right, key);}}}bool _Find(Node* root, const K& key){if (root == nullptr){return false;}if (key < root->_key){return _Find(root->_left, key);}else if (key > root->_key){return _Find(root->_right, key);}else{return true;}}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}

验证代码是否成功:

int main()
{int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };BSTree<int> bst;cout << "非递归版本:" << endl;for (auto e : a){bst.Insert(e);}bst.InOrder();for (auto e : a){bst.Erase(e);bst.InOrder();}cout << "递归版本:" << endl;for (auto e : a){bst.InsertR(e);}bst.InOrder();for (auto e : a){bst.EraseR(e);bst.InOrder();}return 0;
}

实验结果:

在这里插入图片描述
由此可知,这里的二叉搜索树的实现是没有问题的

完整代码:

#include <iostream>
using namespace std;template <class K>
struct Node
{Node(int key = 0):_left(nullptr), _right(nullptr), _key(key){}Node* _left;Node* _right;K _key;
};template <class K>
class BSTree
{typedef Node<K> Node;
public:bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);}else{Node* cur = _root;Node* parent = cur;while (cur){parent = cur;if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return false;}}if (parent->_key > key){parent->_left = new Node(key);}else{parent->_right = new Node(key);}}return true;}bool Erase(const K& key){Node* cur = _root;Node* parent = cur;while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr){// 左为空if (cur == _root){_root = cur->_right;}else{if (key < parent->_key){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr){// 右为空if (cur == _root){_root = cur->_left;}else{if (key < parent->_key){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else{// 左右都不为空parent = cur;Node* subleft = cur->_right;while (subleft->_left){parent = subleft;subleft = subleft->_left;}swap(cur->_key, subleft->_key);if (subleft == parent->_left){parent->_left = subleft->_right;}else{parent->_right = subleft->_right;}}return true;}}return false;}bool Find(const K& key){Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return true;}}return false;}bool InsertR(const K& key){return _Insert(_root, key);}bool EraseR(const K& key){return _Erase(_root, key);}bool FindR(const K& key){return _Find(_root, key);}void InOrder(){_InOrder(_root);cout << endl;}
private:bool _Insert(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (key > root->_key){_Insert(root->_right, key);}else if(key<root->_key){_Insert(root->_left, key);}return false;}bool _Erase(Node*& root, const K& key){if (root==nullptr){return false;}if (key < root->_key){_Erase(root->_left, key);}else if (key > root->_key){_Erase(root->_right, key);}else{if (root->_left == nullptr){Node* del = root;root = root->_right;delete del;return true;}else if (root->_right == nullptr){Node* del = root;root = root->_left;delete del;return true;}else{Node* subleft = root->_right;while (subleft->_left){subleft = subleft->_left;}swap(root->_key, subleft->_key);return _Erase(root->_right, key);}}}bool _Find(Node* root, const K& key){if (root == nullptr){return false;}if (key < root->_key){return _Find(root->_left, key);}else if (key > root->_key){return _Find(root->_right, key);}else{return true;}}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}Node* _root = nullptr;
};

相关文章:

C++:二叉搜索树的原理和模拟实现

文章目录 二叉搜索树二叉搜索树的基本实现原理 二叉搜索树的实现非递归版本的实现递归版本的实现 二叉搜索树 二叉搜索树也叫做二叉排序树&#xff0c;可以是空树&#xff0c;也可以是满足一些要求的二叉树 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点…...

学习视觉CV Transformer (2)--Transformer原理及代码分析

下面结合代码和原理进行深入分析Transformer原理。 2 Transformer深入分析 对于CV初学者来说&#xff0c;其实只需要理解Q K V 的含义和注意力机制的三个计算步骤&#xff1a; Q 和所有 K 计算相似性&#xff1b;对相似性采用 Softmax 转化为概率分布&#xff1b;将概率分布…...

【AI视野·今日CV 计算机视觉论文速览 第271期】Thu, 19 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Thu, 19 Oct 2023 Totally 63 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Learning from Rich Semantics and Coarse Locations for Long-tailed Object Detection Authors Lingchen Meng, Xiyang D…...

GoLong的学习之路(四)语法之循环语句

书接上回&#xff0c;上回说到运算符&#xff0c;这次我们说一个编程语言中最重要的一点&#xff1a;流程控制&#xff0c;及循环语句 文章目录 循环语句if else(分支结构)if条件判断特殊写法 for(循环结构)for range(键值循环) switch casegoto(跳转到指定标签)break(跳出循环…...

【Lua语法】字符串

Lua语言中的字符串是不可变值。不能像在C语言中那样直接改变某个字符串中的某个字符&#xff0c;但是可以通过创建一个新字符串的方式来达到修改的目的 print(add2(1 , 2 ,15,3))a "no one"b string.gsub(a , "no" , "on1111")print(a) print…...

程序员节的由来

早在2006年的时候 我就发现了 1024KB1MB 然后恰好又是2的10次方 那时候我就把这一天定义为程序员节了 不过当时并没有太多的知名度。 所以严格意义来讲 距历史记载&#xff0c;程序员应该是由我&#xff08;田尚滨/cagy&#xff09;发明的。 As early as 2006 I found …...

订水商城H5实战教程-03用户协议

目录 1 创建页面2 为文本组件增加事件3 检查用户协议是否勾选最终效果 我们上一篇介绍了打开首页时弹出登录窗口的功能&#xff0c;本篇我们实现一下用户协议。 1 创建页面 功能是点击用户协议的时候打开具体的协议内容&#xff0c;需要先创建一个页面。打开自定义应用&#x…...

淘宝app商品详情源数据API接口(解决滑块问题)可高并发采集

通过API接口采集淘宝商品列表和app商品详情遇到滑块验证码的解决方法&#xff08;带SKU和商品描述&#xff0c;支持高并发&#xff09;&#xff0c;主要是解决了高频情况下的阿里系滑块和必须要N多小号才能解决的反扒问题&#xff0c;以后都可以使用本方法&#xff1a; 大家都…...

xcode15一直显示正在连接iOS17真机问题解决

前言 更新xcode15之后&#xff0c;出现了各种报错问题&#xff0c;可谓是一路打怪啊&#xff0c;解决一个报错问题又来一个。没想到到了最后还能出现一个一直显示正在连接iOS17真机的问题 一直显示正在连接iOS17真机的问题 问题截图如下&#xff1a; 解决方法 1. 打开De…...

stm32通过AT指令与esp8622通信

stm32通过AT指令与esp8622通信 文章目录 stm32通过AT指令与esp8622通信1.tcp通信2.mqtt通信 1.tcp通信 ATCWMODE1 设置为STA模式ATCWJAP_DEF"langtaotech","langtaotechXXX"ATCIPSTA? 查询ipATCIPMUX0 设置单连接ATCIPSTART"TCP","19…...

Flutter 类似onResume 监听,解决入场动画卡顿

在Flutter 实际开发过程中&#xff0c;页面数据往往是异步加载&#xff0c;接口请求回来后&#xff0c;数据刷新显示到界面上。 由于Flutter性能原因&#xff0c;也可能因为获取数据量比较大&#xff0c;在新页面路由进场动画执行过程中&#xff0c;接口请求结果回来了&#x…...

1024勋章

&#x1f338;关于重阳节的一些发疯日常&#xff08;昨天的聊天记录&#xff0c;今天发系列&#xff09;&#x1f605; &#x1f338;没错&#xff0c;发出来单纯觉得好玩儿&#x1f609;(为了1024勋章&#x1f60f;)芜湖&#xff01;...

C++栈、队列、优先级队列模拟+仿函数

目录 一、栈的模拟和deque容器 1.deque 1.1deque结构 1.2deque优缺点 2.stack模拟 二、队列的模拟 三、priority_queue优先级队列 1.优先级队列模拟 2.添加仿函数 一、栈的模拟和deque容器 在之前&#xff0c;我们学过了C语言版本的栈&#xff0c;可以看这篇文章 栈和…...

ES挂载不上怎么处理?

全文搜索 EelasticSearch安装 Docker安装 docker run -d --name es7 -e ES_JAVA_POTS"-Xms256m -Xmx256m" -e "discovery.typesingle-node" -v /home/206/es7/data/:/usr/share/elasticsearch/data -p 9200:9200 -p 9300:9300 elasticsearch:7.14.0 …...

问题与分类

设计问题 是否已经有类似的解决方案&#xff0c;是否需要当前的设计设计思路的文档话&#xff0c;背景-》 设计思路-》 好处与不足 -》 其他设计思路的对比&#xff08;淘汰其他设计思路的原因&#xff09; 设计思路的评审&#xff0c;如何评审&#xff0c;如何量化&#xff…...

021-Qt 配置GitHub Copilot

Qt 配置GitHub Copilot 文章目录 Qt 配置GitHub Copilot项目介绍 GitHub Copilot配置 GitHub CopilotQt 前置条件升级QtGitHub Copilot 前置条件激活的了GitHub Copilot账号安装 Neovim 启用插件&#xff0c;重启Qt配置 GitHub Copilo安装Nodejs下载[copilot.vim](https://gith…...

如何使用 PostgreSQL 进行数据迁移和整合?

​ PostgreSQL 是一个强大的开源关系型数据库管理系统&#xff0c;它提供了丰富的功能和灵活性&#xff0c;使其成为许多企业和开发者的首选数据库之一。在开发过程中&#xff0c;经常会遇到需要将数据从一个数据库迁移到另一个数据库&#xff0c;或者整合多个数据源的情况。…...

Qt Signals Slots VS QEvents - Qt跨线程异步操作性能测试与选取建议

相关代码参考&#xff1a;https://gitcode.net/coloreaglestdio/qtcpp_demo/-/tree/master/qt_event_signal 1.问题的由来 在对 taskBus 进行低延迟改造时&#xff0c;避免滥用信号与槽起到了较好的作用。笔者在前一篇文章中&#xff0c;叙述了通过避免广播式地播发信号&…...

Postgres 和 MySQL 应该怎么选?

PostgreSQL和MySQL是两个流行的关系型数据库管理系统&#xff08;DBMS&#xff09;。它们都具有一些相似的功能&#xff0c;但也有一些区别。 在选择使用哪个DBMS时&#xff0c;需要考虑多个因素&#xff0c;包括性能、可扩展性、安全性、功能丰富度、生态系统支持等。下面是对…...

【在英伟达nvidia的jetson-orin-nx和PC电脑ubuntu20.04上-装配ESP32开发调试环境-基础测试】

【在英伟达nvidia的jetson-orin-nx和PC电脑ubuntu20.04上-装配ESP32开发调试环境-基础测试】 1、概述2、实验环境3、 物品说明4、参考资料与自我总结5、实验过程1、创建目录2、克隆下载文件3、 拉取子目录安装和交叉编译工具链等其他工具4、添加环境变量6、将样例文件拷贝到桌面…...

从模型到落地:音频降噪技术选型与工程化实战指南

1. 音频降噪技术选型的核心挑战 当你第一次把降噪模型部署到手机端时&#xff0c;大概率会遇到这样的场景&#xff1a;实验室里效果惊艳的模型&#xff0c;在实际设备上要么卡成幻灯片&#xff0c;要么耗电像开了暖手宝。这就是端侧音频降噪最现实的困境——我们必须在效果、算…...

【新能源功率预测】别再只盯准确率了,2026真正决定收益的,是“预测+交易+储能”一体化

关键词&#xff1a; 新能源功率预测、电力现货交易、储能套利、AI大模型、容量电价 2026年的春天&#xff0c;对于新能源电站的投资人和运营者来说&#xff0c;可谓是“冰火两重天”。 “火”的是政策红利终于实质性落地。【发改价格】114号文将独立储能纳入容量电价体系&…...

GLM-4.7-Flash作品集:政务通知、新闻通稿、宣传文案风格迁移生成

GLM-4.7-Flash作品集&#xff1a;政务通知、新闻通稿、宣传文案风格迁移生成 1. 快速上手&#xff1a;用GLM-4.7-Flash玩转文本风格迁移 你是不是经常需要写各种不同类型的文案&#xff1f;今天要写政务通知&#xff0c;明天要写新闻通稿&#xff0c;后天又要写宣传文案&…...

用Anything to RealCharacters为游戏角色“拍照”:生成高质感真人定妆照

用Anything to RealCharacters为游戏角色"拍照"&#xff1a;生成高质感真人定妆照 1. 引言&#xff1a;游戏角色的"数字摄影棚" 想象一下&#xff0c;你精心设计的游戏角色突然从屏幕里走出来&#xff0c;站在真实的摄影棚中&#xff0c;专业的灯光打在他…...

颠覆传统窗口管理:WindowResizer让桌面布局掌控自如

颠覆传统窗口管理&#xff1a;WindowResizer让桌面布局掌控自如 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 你是否曾遇到过这些令人沮丧的场景&#xff1f;精心设计的多显示器…...

Neeshck-Z-lmage_LYX_v2应用落地:国风插画师本地AI绘画工作流搭建

Neeshck-Z-lmage_LYX_v2应用落地&#xff1a;国风插画师本地AI绘画工作流搭建 想成为一名国风插画师&#xff0c;但苦于绘画技巧需要长期积累&#xff1f;或者&#xff0c;你已经是一位创作者&#xff0c;却常常被灵感枯竭和重复性工作所困扰&#xff1f;今天&#xff0c;我将…...

NCM格式高效解密工具:三步解决网易云音乐文件播放限制问题

NCM格式高效解密工具&#xff1a;三步解决网易云音乐文件播放限制问题 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 您是否曾经遇到下载的网易云音乐文件无法在其他设备播放的困扰&#xff1f;ncmdump工具正是为解决这一痛点而生&…...

用Python复刻经典!中国象棋游戏开发中的5个关键问题与解决方案

用Python复刻经典&#xff01;中国象棋游戏开发中的5个关键问题与解决方案 当我在大学第一次尝试用Python实现中国象棋时&#xff0c;本以为只要把棋盘画出来、让棋子能移动就大功告成。直到真正动手编码&#xff0c;才发现那些看似简单的规则背后藏着无数"坑"。比如…...

Qwen3.5推理模型应用实战:快速搭建你的智能学习与代码助手

Qwen3.5推理模型应用实战&#xff1a;快速搭建你的智能学习与代码助手 1. 引言&#xff1a;为什么选择Qwen3.5推理模型 在当今AI技术快速发展的时代&#xff0c;找到一个既轻量又强大的推理模型对于开发者来说至关重要。Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF…...

TurboDiffusion保姆级教程:基于Wan2.1/Wan2.2的AI视频生成快速上手

TurboDiffusion保姆级教程&#xff1a;基于Wan2.1/Wan2.2的AI视频生成快速上手 1. 引言 1.1 为什么选择TurboDiffusion 想象一下&#xff0c;你只需要输入一段文字描述&#xff0c;就能在几秒钟内生成一段高质量的视频。这不是科幻电影里的场景&#xff0c;而是TurboDiffusi…...