【C++进阶03】二叉搜索树

在这里插入图片描述

一、二叉搜索树的概念和性质

中序遍历二叉搜索树会得到一个有序序列
所以二叉搜索树又称二叉排序树
它可以是一棵空树
也可以是具有以下性质的二叉树:

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

二叉搜索树没有相同值的节点
二叉搜索树支持增删查,不支持改
修改会破坏二叉搜索树跟节点比左子树大
右子树小的结构

如图:
在这里插入图片描述

二、二叉搜索树的模拟实现

二叉搜索树节点

// BSTree.h
#pragma once// BinarySearchTree --- BSTree
template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};

二叉搜索树的插入、中序遍历和查找

template<class K>
class BSTree
{typedef BSTreeNode<K> Node; // 名字过长在类里面再typedef,类里受类域限制不会名字冲突
public:bool Insert(const K& key) // 要插入节点内容重复,插入失败返回false{if (_root == nullptr){_root = new Node(key); // 没写构造函数会导致无法将参数 1 从“const K”转换为“const BSTreeNode<K> &”,new的时候会以为你要调转换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{parent->_left = cur;}return true;}bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;}void InOrder() // 中序需要传_root根节点,在类外无法直接访问,所以再套一层。不能用缺省值解决{_InOrder(_root);}// void _InOrder(Node* root = _root) // 缺省值必须是全局变量或是常量,访问_root得用this,而this只能在函数内部使用void _InOrder(Node* root) // 中序{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}private:Node* _root = nullptr;
};

插入的递归实现

bool _InsertR(Node*& root, const K& key) // 用&解决链接问题,最后走到nullptr的位置是上一个节点的别名,很巧妙的链接上
{if (root == nullptr){root = new Node(key);return true;}if (root->_key < key){return _InsertR(root->_right, key);}else if (root->_key > key){return _InsertR(root->_left, key);}else{return false;}
}bool InsertR(const K& key)
{return _InsertR(_root, key);
}

查找的递归实现

bool _FindR(Node* root, const K& key) 
{if (root == nullptr)return false;if (root->_key == key)return true;else if (root->_key < key)return _FindR(root->_right, key);elsereturn _FindR(root->_left, key);return false;
}bool FindR(const K& key) // 递归查找
{return _FindR(_root, key);
}

二叉搜索树的难点在于删除
分别有三种情况

  1. 被删的节点没有孩子节点
  2. 被删的节点只有左孩子或右孩子

第一种情况直接删不用特殊处理
第二种情况将被删节点的孩子节点
连接到他的父节点即可

在这里插入图片描述
3. 被删的节点有两个孩子节点

这时被删的节点的父节点
无法接管他的两个孩子节点
解决方法:
请一个节点替自己接管自己的两个孩子
这个节点可以是左子树最大的节点 or
右子树最小节点

删除接口代码实现

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{// 删除// 1. 左为空if (cur->_left == nullptr){if (cur == _root) // 解决根节点没有父节点的问题{_root = _root->_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 = _root->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}// 3. 左右都不为空else{// 找右树最小节点替换被删节点,也可以是左树最大节点Node* pMinRight = cur;Node* MinRight = cur->_right;while (MinRight->_left){pMinRight = MinRight;MinRight = MinRight->_left;}cur->_key = MinRight->_key;if (pMinRight->_left == MinRight){pMinRight->_left = MinRight->_right;}else{pMinRight->_right = MinRight->_right;}delete MinRight;}return true;  }}return false;
}

删除递归实现

bool _EraseR(Node*& root, const K& key)
{if (root == nullptr)return false;if (root->_key < key){return _EraseR(root->_right, key);}else if (root->_key > key){return _EraseR(root->_left, key);}else{// 删除节点Node* del = root; // 保存要删的节点if (root->_right == nullptr)root = root->_left;else if (root->_left == nullptr)root = root->_right;else{Node* MaxLeft = root->_left;while (MaxLeft->_right){MaxLeft = MaxLeft->_right;}swap(root->_key, MaxLeft->_key);return _EraseR(_root->_left, key); // 转换成子树去删除}delete del;return true;}
}

✨✨✨✨✨✨✨✨
本篇博客完,感谢阅读🌹
如有错误之处可评论指出
博主会耐心听取每条意见
✨✨✨✨✨✨✨✨

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

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

相关文章

PO设计模式详解:从入门到精通一文解读

PO模式&#xff1a; 全称&#xff1a;page objece&#xff0c;分层机制&#xff0c;让不同层去做不同类型的事情&#xff0c;让代码结构清晰&#xff0c;增加复⽤性。 PO模式的优势&#xff1a; 1&#xff09;效率⾼ &#xff1a;同理&#xff0c;PO模式的逻辑层⽅法有具体定…

算法时间空间复杂度计算—空间复杂度

算法时间空间复杂度计算—空间复杂度 空间复杂度定义影响空间复杂度的因素算法在运行过程中临时占用的存储空间讲解 计算方法例子1、空间算法的常数阶2、空间算法的线性阶&#xff08;递归算法&#xff09;3、二分查找分析方法一&#xff08;迭代法&#xff09;方法二&#xff…

干货!一文详解车间管理的五大基本方法

车间管理是制造型企业生产过程中的重要环节&#xff0c;它直接影响着企业的生产效率、成本控制、产品质量以及员工的士气与工作效率。优秀的车间管理不仅能够提升产品的质量和生产力&#xff0c;还能降低运营成本&#xff0c;从而在激烈的市场竞争中为企业赢得优势。 为了帮助…

Rhinos各版本安装指南

下载链接 https://pan.baidu.com/s/1L5qeUPMW32d7zR-GlVVZIw?pwd0531 温馨提示&#xff1a;若您下载的安装包与该安装步骤不同&#xff0c;说明您使用的是之前被淘汰的安装包&#xff0c;请通过该页面的下载链接重新下载。 1.鼠标右击【Rhino8.1(64bit)】压缩包&#xff08…

Vue(一):Vue 入门与 Vue 指令

Vue 01. Vue 快速上手 1.1 Vue 的基本概念 用于 构建用户界面 的 渐进性 框架 构建用户界面&#xff1a;基于数据去渲染用户看到的界面渐进式&#xff1a;不需要学习全部的语法就能完成一些功能&#xff0c;学习是循序渐进的框架&#xff1a;一套完整的项目解决方案&#x…

Spring AOP—深入动态代理 万字详解(通俗易懂)

目录 一、前言 二、动态代理快速入门 1.为什么需要动态代理&#xff1f; : 2.动态代理使用案例&#xff1a; 3.动态代理的灵活性 : 三、深入动态代理 1.需求 : 2.实现 : 2.1 接口和实现类 2.2 提供代理对象的类 2.3 测试类 3.引出AOP : 四、总结 一、前言 第四节内容&…

设备不锈钢二维码标识牌

随着科技的不断发展&#xff0c;二维码已经应用于身边的各个领域。特别是在建筑施工、工业制造、设备管理等领域被广泛应用。 不锈钢二维码的优势。首先&#xff0c;不锈钢材质具有高度耐腐蚀、抗压和耐磨损的特点&#xff0c;可以适应各种极端环境。其次&#xff0c;不锈钢二…

mysql保姆安装教程

一.下载install文件 1.进入Mysql官网&#xff0c;点击下载 2.选择MySQL Installer for Windows 3.推荐选择第二个安装包 4.不登陆&#xff0c;开始下载 5.等待下载完成 二.安装前的配置 通过电脑“设置”&#xff0c;检查电脑是否包含中文名&#xff0c;如果包含请重命名 …

Python中JSON模块的使用

1 JSON简介 JSON是JavaScript Object Notation即Javascript对象简谱的缩写。JSON是一种轻量级的数据交换格式&#xff0c;JSON数据是由键值对组成的结构&#xff0c;与Python中的字典类似&#xff0c;由尖括号包围的键值对组成&#xff0c;键和值的类型可以是字符串、数字、布…

drf知识-08

Django之了解DRF框架 # 介绍&#xff1a;DRF全称 django rest framework # 背景&#xff1a; 在序列化与反序列化时&#xff0c;虽然操作的数据不尽相同&#xff0c;但是执行的过程却是相似的&#xff0c;也就是说这部分代码是可以复用简化编写的 增&#xff1a;校验请…

电子学会C/C++编程等级考试2023年03月(七级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:走出迷宫 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。 假设你已经得到了一个n*m的迷宫的图纸,请你找出从起点到出口的最短路。 时间限制:1000 内存限制…

边缘检测——PidiNet网络训练自己数据集并优化推理测试(详细图文教程)

PiDiNet 是一种用于边缘检测的算法&#xff0c;它提出了一种简单、轻量级但有效的架构。PiDiNet 采用了新 颖的像素差卷积&#xff0c;将传统的边缘检测算子集成到现代 CNN 中流行的卷积运算中&#xff0c;以增强任务性能。 在 BSDS500、NYUD 和 Multicue 上进行了大量的实验…