搜索二叉树

目录

搜索二叉树的性质

搜索二叉树的实现、

插入

 删除

 代码


在以前我们学过二叉树,但是在对二叉树的学习中发现,似乎二叉树并没有什么作用,要论增删它比不上链表,论随机访问也没法和顺序表比,对于当时的我们是一头雾水,那么现在它的功能终于是体现出来了,这里就是我们要讲的搜索二叉树。

搜索二叉树的性质

在这里我们先了解一下什么是搜索二叉树,搜索二叉树,顾名思义它要满足搜索的特征,于是就有人想出来一个办法,我能不能在创建一个树的时候,比它小的值放在左子树,比它大的值放在右子树呢,这样的话当我们要去寻找某一个节点的时候,只需要比较一下左右子树,如果这个值大就往它的右边走,比它小就往它的左边走呢。

 比如这里就是我们的一颗搜索二叉树,当我们要去寻找一个值为6的时候,我就可以先和它的根节点比,小走左边,大走右边。

 按照这个特性,只要一颗搜索二叉树被建立出来了,那么想要寻找一个值是不是时间效率非常的高?答案是否的,在某一个情况下我们想要寻找一个节点消耗的时间也是非常困难的

 比如说是这样的一个搜索二叉树,它在图形上有点像我们的单链表,这样的一棵树如果要去寻找某个节点值的时候效率也是会达到o(N)的。

如果我们在仔细观察一下的话,会发现如果我们对这课树走一个中序遍历的话得到的值会是一个有序的。例如这棵树,如果中序走出来就是

1->3->4->6->7->8->10->13->14

所以我们现在知道二叉树的特性大概有

它的左子树必须是比根节点要小的

它的右子树必须是比根节点要大的

它的中序遍历一定是有序的

搜索二叉树的实现、

插入

要创建一颗二叉树,那么我们在插入数据的时候就要按照二叉树的特征来进行插入,创建很简单,只需要依次寻找,比它小往左,比它大往右,知道找到为空的那个未知就是我们需要插入的值,但是会有一个问题,找到当前为空的时候直接插入并没有把当前节点和这颗树联系起来,所以还要记录一下它的父亲节点。但是这里我们用另一种思路,那么就是传入的时候用引用,这样下一个节点就是上一个节点的引用,给当前节点赋值实际是给上一个节点的左右子树来赋值

 删除

插入看出来其实很简单,这里难的是我们的删除。要删除一个结点可能会遇到四种情况

a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
 

如果要删除的是叶子结点,那么可以直接删除,如果要删除有左孩子就要考虑如果讲左孩子链接道父亲结点,如果是有右孩子就要考虑如果讲右孩子链接上去。如果左右孩子都有这里就要考虑另一种方法替换法。

那么什么是替换法,这里加入我们需要删除的节点为8,那么我们可以选择让左子树最大的节点来替代它。

 这里还要注意一个问题,当我们用左子树最大的机电替换之后需要从左子树的第一个节点作为根节点开始寻找,如果用第一个节点来寻找的话第一次比较比当前节点大会往右边走,最后导致找不到这个节点

 代码

#pragma once
#include<iostream>using namespace std;template<class K>
struct BSNode
{BSNode* _left;BSNode* _right;K _key;BSNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};template<class K>
class BSTree
{
public:typedef BSNode<K> Node;BSTree():_root(nullptr){}BSTree(const BSTree<int>& t){_root = _copy(t._root);}bool FindR(const K& key){return _FindR(_root,key);}bool Insert(const K& key){return _Insert(_root, key);}void Inorder(){_Inorder(_root);}bool erase(const K& key){return _erase(_root, key);}~BSTree(){destor(_root);}
private:Node* _copy(const Node* t){if (t == nullptr)return nullptr;Node* copynode = new Node(t->_key);copynode->_left = _copy(t->_left);copynode->_right = _copy(t->_right);return copynode;}bool _Insert(Node*& root,const K& key){if (root == nullptr){root = new Node(key);		//这里可以直接这样插入是因为当前结点是root-左右指向的引用return true;}//开始往左右两边去找插入的未知if (root->_key < key){return _Insert(root->_right,key);	}else if (root->_key > key){return _Insert(root->_left, key);}else{return false;}}bool _erase(Node*& root, const K& key){if (root == nullptr)		//先判断是否为空树return false;if (root->_key < key)	//如果要删除的值比当前节点大{	return _erase(root->_right,key);	//开始往右边递归}else if (root->_key > key)	//如果要删除的值比当前节点小{return _erase(root->_left,key);	//开始往左边递归}else{//删除有左或右孩子的情况if (root->_left == nullptr)	//如果它的左子树为空{root = root->_right;	//那么就让它的右节点等于当前节点}else if (root->_right == nullptr)//如果它的右子树为空{root = root->_left;//那么就让它的左节点等于当前节点}//左右都有孩子的情况else{Node* del = root;Node* leftMax = root->_left;	while (leftMax->_right){leftMax = leftMax->_right;	//用左孩子最大的节点来替换当前要删除的节点}swap(root->_key, leftMax->_key);_erase(root->_left, key);	//这里不能从第一个节点开始找,因为当前树的节点已经被替换过了,如果从第一个节点开始找会导致找不到这个节点del = leftMax;	delete del;	//找到之后删除当前节点return true;}}}bool _FindR(const Node* root,const K& key){if (root == nullptr)return false;if (root->_key < key){return _FindR(root->_right);}else if (root->_key > key){return _FindR(root->_left);}else{return true;}}void _Inorder(Node* root){if (root == nullptr)return;_Inorder(root->_left);cout << root->_key << " ";_Inorder(root->_right);}void destor(Node* root){if (root == nullptr)return;destor(root->_left);destor(root->_right);delete root;root = nullptr;}Node* _root;
};//测试#pragma once#include"RecursiveBinarySearchTree.h"
using namespace std;int main()
{int arr[] = { 8,3,10,1,6,14,4,7,13 };BSTree<int> t;for (auto e : arr){t.Insert(e);}t.Inorder();t.erase(6);t.erase(1);t.erase(8);t.erase(13);cout << endl;t.Inorder();cout << endl;BSTree<int> t1(t);t1.Inorder();return 0;
}

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

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

相关文章

[Go版]算法通关村第十一关白银——位运算的高频算法题

目录 专题1&#xff1a;位移的妙用题目&#xff1a;位1的个数&#xff08;也被称为汉明重量&#xff09;解法1&#xff1a;遍历所有位&#xff0c;判断每个位的数字是否是1Go代码 解法2&#xff1a;依次消除每个1的位 numnum&(num-1)Go代码 题目&#xff1a;比特位计数思路…

Mac 卸载appium

安装了最新版的appium 2.0.1,使用中各种问题&#xff0c;卡顿....,最终决定回退的。记录下卸载的过程 1.打开终端应用程序 2.卸载全局安装的 Appium 运行以下命令以卸载全局安装的 Appium&#xff1a; npm uninstall -g appium 出现报错&#xff1a;Error: EACCES: permiss…

云安全攻防(十二)之 手动搭建 K8S 环境搭建

手动搭建 K8S 环境搭建 首先前期我们准备好三台 Centos7 机器&#xff0c;配置如下&#xff1a; 主机名IP系统版本k8s-master192.168.41.141Centos7k8s-node1192.168.41.142Centos7k8s-node2192.168.41.143Centos7 前期准备 首先在三台机器上都执行如下的命令 # 关闭防火墙…

Python读取Word统计词频输出到Excel

1.安装依赖的包 "# 读取docx\n", "!pip install python-docx\n", "!pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx\n", "# 中英文分词\n", "!pip install jieba\n", "!pi…

postman测试后端增删改查

目录 一、本文介绍 二、准备工作 &#xff08;一&#xff09;新建测试 &#xff08;二&#xff09;默认url路径查看方法 三、增删改查 &#xff08;一&#xff09;查询全部 &#xff08;二&#xff09;增加数据 &#xff08;三&#xff09;删除数据 &#xff08;四&…

nginx反向代理流程

一、nginx反向代理流程 反向代理&#xff1a;使用代理服务器来接受internet上的连接请求&#xff0c;然后将请求转发给内部网络中的上游服务器&#xff0c;并将上游服务器得到的结果返回给请求连接的客户端&#xff0c;代理服务器对外表现就是一个web服务器。Nginx就经常拿来做…

【内网穿透】如何实现在外web浏览器远程访问jupyter notebook服务器

文章目录 前言1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 前言 Jupyter Notebook&#xff0c;它是一个交互式的数据科学和计算环境&#xff0c;支持多种编程语言&#xff0c;如…

信也科技一面凉经

1.在项目经历里挑一个详细介绍一下 项目的应用场景 2.项目里用到多线程是怎么用的&#xff1f;回答&#xff1a;线程池 用通过 ThreadPoolExecutor 构造函数的方式创建的线程池 3.线程池有哪些重要参数&#xff1f;回答&#xff1a;核心线程数、最大线程数、阻塞队列类型、…

【爱书不爱输的程序猿】公网访问本地搭建的WEB服务器之详细教程

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本地电脑搭建Web服务器并用cpolar发布至公网访问 前言1. 首先将PHPStudy、WordPress、cpolar下载到电脑2. 安装PHPStudy3. 安装cpolar&#xff0c;进入Web-UI界面4.安装wordpress5.…

KU Leuven TU Berlin 推出“RobBERT”,一款荷兰索塔 BERT

荷兰语是大约24万人的第一语言&#xff0c;也是近5万人的第二语言&#xff0c;是继英语和德语之后第三大日耳曼语言。来自比利时鲁汶大学和柏林工业大学的一组研究人员最近推出了基于荷兰RoBERTa的语言模型RobBERT。 谷歌的BERT&#xff08;来自Transformers的B idirectional …

C语言 常用工具型API --------system()

函数名&#xff1a; system&#xff08;&#xff09; 用 法&#xff1a; int system(char *command); 原理&#xff1a; 创建一个子进程去加载一个新程序执行&#xff0c;而Linux命令基本都是一个单独的进程实现的&#xff0c;所以你所掌握的Linux命令越多&#xff0c;该函数…

AUTOSAR规范与ECU软件开发(实践篇)4.2 基于Matlab/Simulink的软件组件开发

目录 前言 1 、Matlab/Simulink与AUTOSAR基本概念的对应关系 2 、软件组件内部行为建模方法

由浅入深学习Tapable

文章目录 由浅入深学习TapableTapable是什么Tapable的Hook分类同步和异步的 使用Sync*同步类型钩子基本使用bailLoopWaterfall Async*异步类型钩子ParallelSeries 由浅入深学习Tapable webpack有两个非常重要的类&#xff1a;Compiler和Compilation。他们通过注入插件的方式&a…

CentOS系统环境搭建(一)——Centos7更新

Centos7更新 更新 yum&#xff08;包括centos内核&#xff09; yum update执行后&#xff0c;系统将更新到centos 7.9。 从这一篇文章开始开始&#xff0c;我将开始在centos系统环境搭建&#x1f517;https://blog.csdn.net/weixin_43982359/category_12411496.html中开始对C…

【数据分析入门】Numpy进阶

目录 一、数据重塑1.1 透视1.2 透视表1.3 堆栈/反堆栈1.3 融合 二、迭代三、高级索引3.1 基础选择3.2 通过isin选择3.3 通过Where选择3.4 通过Query选择3.5 设置/取消索引3.6 重置索引3.6.1 前向填充3.6.2 后向填充 3.7 多重索引 四、重复数据五、数据分组5.1 聚合5.2 转换 六、…

回溯算法详解

目录 回溯算法详解 回溯VS递归 回溯算法的实现过程 n个结点构造多本节要讨论的是当给定 n&#xff08;n>0&#xff09;个结点时&#xff0c;可以构建多少种形态不同的树。 回溯算法详解 回溯算法&#xff0c;又称为“试探法”。解决问题时&#xff0c;每进行一步&#…

主成分分析Python代码

对于主成分分析详细的介绍&#xff1a;主成分分析&#xff08;PCA&#xff09;原理详解https://blog.csdn.net/zhongkelee/article/details/44064401 import numpy as np import pandas as pd标准PCA算法 def standeredPCA(data,N): #data:…

【golang】链表(List)

List实现了一个双向链表&#xff0c;而Element则代表了链表中元素的结构。 可以把自己生成的Element类型值传给链表吗&#xff1f; 首先来看List的四种方法。 MoveBefore方法和MoveAfter方法&#xff0c;它们分别用于把给定的元素移动到另一个元素的前面和后面。 MoveToFro…

十种排序算法(附动图)

排序算法 一、基本介绍 ​ 排序算法比较基础&#xff0c;但是设计到很多计算机科学的想法&#xff0c;如下&#xff1a; ​ 1、比较和非比较的策略 ​ 2、迭代和递归的实现 ​ 3、分而治之思想 ​ 4、最佳、最差、平均情况时间复杂度分析 ​ 5、随机算法 二、排序算法的分类 …

RabbitMq-1基础概念

RabbitMq-----分布式中的一种通信手段 1. MQ的基本概念&#xff08;message queue,消息队列&#xff09; mq:消息队列&#xff0c;存储消息的中间件 分布式系统通信的两种方式&#xff1a;直接远程调用&#xff0c;借助第三方完成间接通信 消息的发送方是生产者&#xff0c…