搜索二叉树

目录

搜索二叉树的性质

搜索二叉树的实现、

插入

 删除

 代码


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

搜索二叉树的性质

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

 比如这里就是我们的一颗搜索二叉树,当我们要去寻找一个值为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 前期准备 首先在三台机器上都执行如下的命令 # 关闭防火墙…

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;如…

【爱书不爱输的程序猿】公网访问本地搭建的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 …

由浅入深学习Tapable

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

【数据分析入门】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:…

十种排序算法(附动图)

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

RabbitMq-1基础概念

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

面试热题(二叉树的锯齿形层次遍历)

给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3…

C++ STL stack queue

目录 一.stack 介绍 二.stack 使用 三.stack 模拟实现 普通版本&#xff1a; 适配器版本&#xff1a; 四.queue的介绍 五. queue使用 六.queue模拟实现 七.deque介绍 1.容器适配器 2.deque的简单介绍 3.deque的缺陷 4.为什么选择deque作为stack和queue的底层默认容…

pycharm调整最大堆发挥最大

python程序运行时&#xff0c;怎么提高效率&#xff0c;设置pycharm最大堆过程如下&#xff1b; 一、进入设置pycharm最大堆&#xff1b; 二、进入设置pycharm最大堆&#xff1b; 如果8g设置为6g左右&#xff0c;占75%左右最佳

【JVM】JVM中的分代回收

文章目录 分代收集算法什么是分代分代收集算法-工作机制MinorGC、 Mixed GC 、 FullGC的区别是什么 分代收集算法 什么是分代 在java8时&#xff0c;堆被分为了两份&#xff1a; 新生代和老年代【1&#xff1a;2】 其中&#xff1a; 对于新生代&#xff0c;内部又被分为了三…

Socks5代理在多线程爬虫中的应用

在进行爬虫开发过程中&#xff0c;我们常常需要处理大量的数据&#xff0c;并执行多任务并发操作。然而&#xff0c;频繁的请求可能会引起目标网站的反爬机制&#xff0c;导致IP封禁或限制访问。为了规避这些限制&#xff0c;我们可以借助Socks5代理的强大功能&#xff0c;通过…

Nginx反向代理技巧

跨域 作为一个前端开发者来说不可避免的问题就是跨域&#xff0c;那什么是跨域呢&#xff1f; 跨域&#xff1a;指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的&#xff0c;是浏览器对javascript施加的安全限制。浏览器的同源策略是指协议&#xff0c;域名…