C++进阶篇3---二叉搜索树(Binary Search Tree)

一、二叉搜索树的概念

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

根据二叉搜索树的性质,我们很容易看出它的中序遍历是升序,下面画一个二叉搜索树,可以试着用中序遍历遍历一遍,对二叉树有所遗忘的可以去看看二叉树详解

 

二、二叉搜索树的实现

//定义结点
template<class T>
struct BSTreeNode {T val;BSTreeNode* left;BSTreeNode* right;BSTreeNode(const T& x):val(x),left(nullptr),right(nullptr){}
};template<class T>
class BSTree {typedef BSTreeNode<T> Node;
public:void InOrder();//中序遍历Node* Find(const T& x);//查找bool Insert(const T& x);//插入bool Erase(const T& x);//删除
private:Node*_root;
};

注意:下面代码涉及的递归函数都是写了两层,一层供对象调用,一层实现底层逻辑,因为_root被设置为了私有成员,而树的操作基本都需要遍历,所以通过成员函数实现对_root的使用

1.中序遍历

//这里二叉树的递归函数建议写两层,因为_root是私有成员只能在类内访问
void _InOrdered(Node* root) //该函数可以设为私有/保护,仅供类内使用,具体在场景
{if (root == __nullptr)return;_InOrdered(root->left);cout << root->val << " ";_InOrdered(root->right);
}void InOrdered()
{_InOrdered(_root);cout << endl;
}

2.查找

2.1迭代

Node* Find(const T& x) {Node* cur = _root;while (cur) {if (cur->val == x)return cur;else if (cur->val > x)cur = cur->left;elsecur = cur->right;}return nullptr;
}

2.2递归

	
Node* _FindR(Node* root, const T& x) 
{if (root->val > x)return _FindR(root->left, x);else if (root->val < x)return _FindR(root->right, x);elsereturn root;return nullptr;
}Node* FindR(const T& x) 
{return _FindR(_root, x);
}

3.插入

  • 二叉搜索树中没有重复元素

3.1迭代

bool Insert(const T& x) 
{if (_root == nullptr) //为空树,直接插入{_root = new Node(x);return true;}Node* cur = _root;Node* parent = nullptr;while (cur) {parent = cur;if (cur->val < x)cur = cur->right;else if (cur->val > x)cur = cur->left;else//出现该值出现过return false;}Node* newnode = new Node(x);if (parent->val > x) parent->left = newnode;else parent->right = newnode;return true;
}

3.2递归

bool _InsertR(Node*& root,const T& x) //注意这里的引用
{if (root == nullptr) {root = new Node(x);//这是引用,不是变量,不用担心连接问题,本质和用二级指针一样return true;}if (root->val > x)return _InsertR(root->left, x);else if (root->val < x)return _InsertR(root->right, x);elsereturn false;
}bool InsertR(const T& x) {return _InsertR(_root, x);
}

4.删除(重点)

 4.1迭代

bool Erase(const T& x) 
{Node* cur = _root;Node* parent = nullptr;while (cur) {int val = cur->val;if (x < val) {parent = cur;cur = cur->left;}else if (x > val) {parent = cur;cur = cur->right;}else {if (cur->left == nullptr) //左为空{if (parent->val > x)parent->left = cur->right;elseparent->right = cur->right;}else if (cur->right == nullptr)//右为空{if (parent->val > x)parent->left = cur->left;elseparent->right = cur->left;}else//左右都不为空{//这里采取在右子树种找最小结点Node* L = cur->right;Node* fa = cur;while (L->left) {fa = L;L = L->left;}swap(L->val, cur->val);if (fa != cur)fa->left = nullptr;else//这里需要注意如果最小结点就是右子树的根结点的情况fa->right = L->right;cur = L;}delete cur;return true;}}return false;
}

4.2递归

bool _EraseR(Node*& root, const T& x) //注意这里的引用
{if (root == nullptr)return false;if (root->val > x)return _EraseR(root->left, x);else if (root->val < x)return _EraseR(root->right, x);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(subleft->val, root->val);return _EraseR(root->right, x);//将问题转化为更小的子问题}}
}bool EraseR(const T& x) 
{return _EraseR(_root, x);
}

三、完整版

template<class T>
struct BSTreeNode {T val;BSTreeNode* left;BSTreeNode* right;BSTreeNode(const T& x):val(x),left(nullptr),right(nullptr){}
};template<class T>
class BSTree {typedef BSTreeNode<T> Node;
public:bool Insert(const T& x) {if (_root == nullptr) {_root = new Node(x);return true;}Node* cur = _root;Node* parent = nullptr;while (cur) {parent = cur;if (cur->val < x) {cur = cur->right;}else if (cur->val > x) {cur = cur->left;}else{return false;}}Node* newnode = new Node(x);if (parent->val > x) parent->left = newnode;else parent->right = newnode;return true;}Node* find(const T& x) {Node* cur = _root;while (cur) {if (cur->val == x)return cur;else if (cur->val > x)cur = cur->left;elsecur = cur->right;}return nullptr;}bool erase(const T& x) {Node* cur = _root;Node* parent = nullptr;while (cur) {int val = cur->val;if (x < val) {parent = cur;cur = cur->left;}else if (x > val) {parent = cur;cur = cur->right;}else {if (cur->left == nullptr) //左为空{if (parent->val > x)parent->left = cur->right;elseparent->right = cur->right;}else if (cur->right == nullptr)//右为空{if (parent->val > x)parent->left = cur->left;elseparent->right = cur->left;}else//左右都不为空{Node* L = cur->right;Node* fa = cur;while (L->left) {fa = L;L = L->left;}swap(L->val, cur->val);if (fa != cur)fa->left = nullptr;elsefa->right = L->right;cur = L;}delete cur;return true;}}return false;}void _InOrdered(Node* root) {if (root == __nullptr)return;_InOrdered(root->left);cout << root->val << " ";_InOrdered(root->right);}void InOrdered() {_InOrdered(_root);cout << endl;}Node* FindR(const T& x) {return _FindR(_root, x);}bool InsertR(const T& x) {return _InsertR(_root, x);}bool EraseR(const T& x) {return _EraseR(_root, x);}//BSTree() {}BSTree() = default;//强制生成默认构造~BSTree(){Destroy(_root);}BSTree(const BSTree& t) {_root = Copy(t._root);}BSTree& operator=(const BSTree t){swap(t._root);return *this;}
private:Node* Copy(Node* root) {if (root == nullptr)return nullptr;Node* newnode = new Node(root->val);newnode->left = Copy(root->left);newnode->right = Copy(root->right);return newnode;}void Destroy(Node*& root) {if (root == nullptr)return;Destroy(root->left);Destroy(root->right);delete root;root = nullptr;}bool _EraseR(Node*& root, const T& x) {if (root == nullptr)return false;if (root->val > x)return _EraseR(root->left, x);else if (root->val < x)return _EraseR(root->right, x);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(subleft->val, root->val);return _EraseR(root->right, x);}}}bool _InsertR(Node*& root,const T& x) {if (root == nullptr) {root = new Node(x);return true;}if (root->val > x)return _InsertR(root->left, x);else if (root->val < x)return _InsertR(root->right, x);elsereturn false;}Node* _FindR(Node* root, const T& x) {if (root->val > x)return _FindR(root->left, x);else if (root->val < x)return _FindR(root->right, x);elsereturn root;return nullptr;}
private:Node* _root = nullptr;
};

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

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

相关文章

基于jquery+html开发的json格式校验工具

json简介 JSON是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式&#xff0c;但是也使用了类似于C语言家族…

Django 尝试SSE报错 AssertionError: Hop-by-hop headers not allowed 的分析

情况描述 近期计划测试一下django对日志打印的支持&#xff0c;一般都是用websocket的方式&#xff0c;想测试一下SSE (Server-sent events)的服务端推送&#xff0c;发现过程中存在报错&#xff1a; Traceback (most recent call last):File "D:\Software\Anaconda3\li…

shell中的运算

目录 1.运算符号 2.运算指令 练习 1.运算符号 运算符号意义加法-减法*乘法/除法%除法后的余数**乘方自加一- -自减一<小于<小于等于>大于>大于等于等于ji ->jji*j*i->jj*i/j/i->jj/i%j%i->jj%i 2.运算指令 (()) //((a12))let //let a12 …

[动态规划] (一) LeetCode 1137.第N个泰波那契数

[动态规划] (一) LeetCode 1137.第N个泰波那契数 文章目录 [动态规划] (一) LeetCode 1137.第N个泰波那契数题目解析解题思路状态表示状态转移方程初始化和填表顺序返回值 代码实现总结空间优化代码实现 总结 1137. 第 N 个泰波那契数 题目解析 解题思路 状态表示 (1) 题目要…

正点原子嵌入式linux驱动开发——Linux 串口RS232/485/GPS 驱动

串口是很常用的一个外设&#xff0c;在Linux下通常通过串口和其他设备或传感器进行通信&#xff0c;根据 电平的不同&#xff0c;串口分为TTL和RS232。不管是什么样的接口电平&#xff0c;其驱动程序都是一样的&#xff0c;通过外接RS485这样的芯片就可以将串口转换为RS485信号…

97. 交错字符串

题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 解题思路&#xff1a;动态规划。 如果s1.length()s2.length ! s3.length()&#xff0c;直接返回false&#xff0c;否则使用动态规划求解。定义状态&#xff1a;dp[i][i]&#xff…

解决找不到vcruntime140.dll,无法继续执行代码方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到vcruntime140.dll”。这个错误通常发生在运行某些程序或游戏时&#xff0c;它会导致程序无法正常启动或运行。那么&#xff0c;找不到vcruntime140.dll&#xff0c;无法继续执行代码…

word中批注内容显示设置

在修改他人word时&#xff0c;有时候保存为pdf需要有选择性的显示&#xff0c;如下图&#xff0c;原始修改方式包括三种&#xff1a;批注、格式修改、删除添加&#xff0c;如下图所示&#xff1a; 有时候不想要格式设置说明&#xff0c;则只需要进行在审阅--显示标志--不勾选设…

【Java 进阶篇】解决Java Web应用中请求参数中文乱码问题

在Java Web应用开发中&#xff0c;处理请求参数时经常会遇到中文乱码的问题。当浏览器向服务器发送包含中文字符的请求参数时&#xff0c;如果不正确处理&#xff0c;可能会导致乱码问题&#xff0c;使得参数无法正确解析和显示。本文将详细探讨Java Web应用中请求参数中文乱码…

qt高精度定时器的使用停止线程应用

##线程停止 //线程停止应用 public: explicit WorkerThread(QObject *parent 0) :QThread(parent), m_bStopped(false){qDebug() << "Worker Thread : " << QThread::currentThreadId();}~WorkerThread(){stop();quit();wait();}void stop() {qDebug()…

共用体开发案例

有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。要求用同一个表格来处理。 #include <stdio.h>struct Person {char name[32];int age;char zhiYe;char addr[32];union {int class;…

JDBC与MySql数据库

一、系统开发前的环境准备 1.下载Mysql 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 文件解压缩到本地 在此路径下新增my.ini文件以及新建data文件夹 编辑my.ini文件 配置环境变量 注意是编辑系统变量的Path 以管理员身份运行cmd 输入命令&#xff1a…

VDA到Excel方案介绍之自定义邮件接收主题

VDA标准是德国汽车工业协会&#xff08;Verband der Automobilindustrie&#xff0c;简称VDA&#xff09;制定的一系列汽车行业标准。这些标准包括了汽车生产、质量管理、供应链管理、环境保护、安全性能等方面的规范和指南。VDA标准通常被德国和国际上的汽车制造商采用&#x…

【机器学习】sklearn特征值选取与处理

sklearn特征值选取与处理 文章目录 sklearn特征值选取与处理1. 调用数据集与数据集的划分2. 字典特征选取3. 英文文本特征值选取4. 中文特征值选取5. 中文分词文本特征抽取6. TfidfVectorizer特征抽取7. 归一化处理8. 标准化处理9. 过滤低方差特征10. 主成分分析11. 案例&#…

制作自己的前端组件库并上传到npm上

最近实现了自己的一个前端组件库demo&#xff0c;目前只上传了几个小组件。话不多说&#xff0c;上图&#xff1a; 我分了三个项目&#xff1a;yt-ui组件库、使用文档、demo。线上地址如下&#xff1a; [yt-ui组件库](mhfwork/yt-ui - npm) [组件库使用文档](介绍 | mhfwork/y…

docker应用部署---Tomcat的部署配置

1. 搜索tomcat镜像 docker search tomcat2. 拉取tomcat镜像 docker pull tomcat3. 创建容器&#xff0c;设置端口映射、目录映射 # 在/root目录下创建tomcat目录用于存储tomcat数据信息 mkdir ~/tomcat cd ~/tomcatdocker run -id --namec_tomcat \ -p 8080:8080 \ -v $PWD:…

拓扑排序详解

拓扑排序 如果说最短路径是有环图的应用&#xff0c;那么拓扑排序就是无环图的应用。 拓扑排序介绍 我们会把施工过程、生产流程、软件开发、教学安排等都当成- -个项目工程来对待&#xff0c;所有的工程都可分为若干个“活动”的子工程。例如下图是我这非专业人士绘制的一张…

bbr 流相互作用图示

类似 AIMD 收敛图&#xff0c;给出 bbr 的对应图示&#xff1a; bbr 多流相互作用非常复杂&#xff0c;和右下角的 AIMD 相比&#xff0c;毫无美感&#xff0c;但是看一眼左下角的 bbr 单流情况&#xff0c;又过于简陋&#xff0c;而 bbr 的核心就基于这简陋的假设。 浙江温…

ChatGPT从入门到精通

目录 什么是ChatGPT&#xff1f;ChatGPT能帮我干什么&#xff1f;标题在哪里可以使用ChatGPT&#xff1f;什么是ILoveChatGPT&#xff08;IMYAI&#xff09;&#xff1f;标题如何拥有头像&#xff1f;如何获取更多对话次数&#xff1f;!标题如何提问GPT&#xff1f;如何正确地利…

【黑马程序员】mysql进阶再进阶篇笔记

64. 进阶-锁-介绍(Av765670802,P121) 为了应对不同场景 全局锁-所有表 表计锁 一张表 行级锁 一行数据 65. 进阶-锁-全局锁-介绍(Av765670802,P122) 66. 进阶-锁-全局锁-一致性数据备份(Av765670802,P123) 67. 进阶-锁-表级锁-表锁(Av765670802,P124) 读锁、写锁 68. 进阶…