树之二叉排序树(二叉搜索树)

什么是排序树

说一下普通二叉树可不是左小右大的 

插入的新节点是以叶子形式进行插入的

二叉排序树的中序遍历结果是一个升序的序列

下面是两个典型的二叉排序树 

 

 

 二叉排序树的操作

 构造树的过程即是对无序序列进行排序的过程

 存储结构

 通常采用二叉链表作为存储结构 不能

 插入算法

 

 下面插入一个图解

上面的×就表示会在当前位置给delete掉一个结点 

 查找算法

 

 删除算法

  

 

第三种情况:你删除的结点下面就是说还有左右子树,那么这个时候,我们就要去找到这棵树中序遍历结果之后的直接前驱或者直接后继,然后把这个前驱或者后继给按到删除结点这个位置上,将它下面的树移到被替换结点的位置

删除操作的具体讲解

重点讲解一下删除节点的核心分析

这里在补一张中序遍历的递归调用图

 

  直接上代码

在上代码之前,先来说一下,二叉搜索树很多方法都利用了递归的思想,许多说明我都放到代码注释里面了,可以结合下面的这张图进行思维分析

 

先来看c语言代码(algorithm/bst/bst1.c)

#include <stdio.h>
#include <stdlib.h>typedef int key_type;
typedef struct _node
{key_type key;struct _node *left;struct _node *right;
}node, *pnode;void insert_bst(pnode *root, key_type key)
{//初始化插入结点pnode p = (pnode)malloc(sizeof(node));if (p != NULL){p->key = key;//把值给放进去p->left = p->right = NULL;}//空树的时候,直接作为根结点if (*root == NULL){*root = p;return;}//插入到当前结点的左孩子if ((*root)->left == NULL && (*root)->key > key){(*root)->left = p;//直接在堆上面指就可以了return;}//插入到当前结点的右孩子if ((*root)->right == NULL && (*root)->key < key){(*root)->right = p;return;}//上面都没有进入,说明结点就要往下继续存放//需要先把我们分配的结点内存给释放掉free(p);//左子树递归if ((*root)->key > key) {insert_bst(&(*root)->left, key);}//右子树递归else if((*root)->key < key) {insert_bst(&(*root)->right, key);}
}//根据关键字删除某个结点,成功返回1,失败返回0
int delete_bst(pnode *root, key_type key)
{if (*root == NULL){return 0;//这是一棵空树}if ((*root)->key == key){pnode pbak1, pmove;//判断右子树是否为空,为空,只需要重接左子树if ((*root)->right == NULL){//把当前结点的左子树接上去就可以了pbak1 = *root;//当前结点备份等会释放//改变在栈上面一级指针的指向*root = (*root)->left;//删除free(pbak1); }//左子树为空的情况下,只需要重接右子树就行了else if ((*root)->left == NULL){//删除结点的空间备份pbak1 = *root;*root = (*root)->right;//改变栈上结点的指向free(pbak1);}//左右子树都不为空else{//我们要找到直接前驱或者一个直接后继//前驱就是当前结点下一个结点左边结点的右边(尽头),所以先把root指向了左结点pbak1 = *root;//删除结点的一个备份pmove = (*root)->left;//左边等会要接接上//再来循环右边//注意的问题是我们需要指向一个直接前驱的父结点//以便于用来更改当前的子树结点,也就是被删除结点的下一个结点要连接上去while (pmove->right){pbak1 = pmove;//前驱结点的父节点pmove = pmove->right;//这个是指向了我们需要的前驱结点}//s指向了前驱结点,将s放到root结点上面(*root)->key = pmove->key;//改变了值,不是地址,等会吧pmove给释放掉//重接一下下面结点的子树//如果pbak1没有移动过,那么pbak1->left = pmove ->left;if (pbak1 == *root){pbak1->left = pmove->left;}else {//如果移动过,那么pbak1->right就要改变pbak1->right = pmove->left;}//释放掉pmove这个结点free(pmove);}return 1;}//没有找到的情况下,我们需要遍历树else if (key < (*root)->key) {//直接走左子树//这里必须return ,不然找到了也会falsereturn delete_bst(&(*root)->left, key);}else if (key > (*root)->key){//大于当前结点就直接走右子树return delete_bst(&(*root)->right, key);}return 0;
}//查找元素,找到返回结点指针,没找到返回NULL
//找结点,传入一个一级指针就好了
pnode search_bst(pnode root, key_type key)
{if (root == NULL){return NULL;}//查找右子树if (key > root->key){return search_bst(root->right, key);}//查找左子树else if (key < root->key){return search_bst(root->left, key);}else {return root;}
}//查找最小的关键字,空树时返回NULL
pnode search_min_bst(pnode root)
{if (root == NULL){return NULL;}//最小的话应该就是最左边孩子if (root->left == NULL){return root;//叶子结点下面都是NULL}else {return search_min_bst(root->left);}
}//查找最大关键字,空树时返回NULL
pnode search_max_bst(pnode root)
{if (root == NULL){return NULL;}//找到最后的孩子if (root->right == NULL){return root;}else{//一直往右边找,直到没有有孩子结点return search_max_bst(root->right);}
}//中序遍历二叉树
void inorder_traverse_bst(pnode root)
{if (root != NULL){//遍历左子树//先走到最左边,依次调用结束,返回打印inorder_traverse_bst(root->left);//走到最后一个结束,打印,中间根结点也会打印printf("%d ", root->key);//然后走右边开始打印inorder_traverse_bst(root->right);}
}int main()
{//创建一棵二叉树pnode root = NULL;insert_bst(&root, 3);insert_bst(&root, 8);insert_bst(&root, 2);insert_bst(&root, 5);insert_bst(&root, 4);insert_bst(&root, 9);insert_bst(&root, 11);//中序遍历二叉树inorder_traverse_bst(root);delete_bst(&root, 2);printf("\n---------------------\n");inorder_traverse_bst(root);return 0;
}

再来看java的运行代码(algorithm/bst1)

package com.pxx.tree.bst1;
class Node {int key;Node left, right;//这里就是在new的时候可以出初始化一个头结点public Node(int key) {this.key = key;this.left = this.right = null;}
}class BstTree {//插入结点public Node insertBst(Node root, int key) {if (root == null) {//直接返回这个新结点//指到最后可添加位置,也是直接指向这个新节点return new Node(key);}if (key < root.key) {//往左边走root.left = insertBst(root.left, key);} else if(key > root.key) {//往右边走root.right = insertBst(root.right, key);}return root;//这里返回root的意思也就是中间的结点必须连上}//删除结点public Node deleteBST(Node root, int key) {if (root == null) {return root;}if (key < root.key) {root.left = deleteBST(root.left, key);} else if (key > root.key) {root.right = deleteBST(root.right, key);} else {//找到了这个结点if (root.left == null) {//直接返回这个结点的右结点给上一个节点return root.right;} else if (root.right == null) {return root.left;}//上面都没有进入,说明有左右子树,需要结点上一移动//先改变查找到结点的值,我们需要用它的直接后继来替换//也就是找到它右边的结点,然后不停的左边,一直到尽头root.key = minValue(root.right);//改变结点之间的连接root.right = deleteBST(root.right, root.key);}return root;}// 寻找最小值//从某个结点一直找到最左边就是最小值public int minValue(Node root) {while (root != null && root.left != null) {root = root.left;}return root.key;}//中序遍历这个结点public void inorderTraverseBst(Node root) {if (root != null) {//先打印左边inorderTraverseBst(root.left);System.out.print(root.key + " ");inorderTraverseBst(root.right);}}//查找某一个元素public Node searchBST(Node root, int key) {if (root == null || root.key == key) {return root;}if (key < root.key) {return searchBST(root.left, key);}return searchBST(root.right, key);}}public class Solution {public static void main(String[] args) {BstTree bstTree = new BstTree();Node root = null;//root在堆上就已经建立空间root = bstTree.insertBst(root, 3);bstTree.insertBst(root, 8);bstTree.insertBst(root,2);bstTree.insertBst(root,5);bstTree.insertBst(root,4);bstTree.insertBst(root,9);bstTree.insertBst(root,1);//中序遍历这片空间bstTree.inorderTraverseBst(root);System.out.println("-----------------");bstTree.deleteBST(root,2);bstTree.deleteBST(root,8);bstTree.inorderTraverseBst(root);}}

好了,说到这。

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

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

相关文章

内网如何使用Python第三方库包(举例JustinScorecardPy)

内网如何使用Python第三方库包 一、下载python whl文件(官网有的) 1、第一种方法 要直接下载whl文件&#xff0c;你可以按照以下步骤操作&#xff1a; 首先&#xff0c;访问 https://pypi.org/ 或 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 网站。这两个都是Python的官方…

光刻掩膜版怎么制作的?

光掩膜版基本上是 IC 设计的“主模板”。掩模版有不同的尺寸。常见尺寸为 6 x 6 英寸一般的掩膜版由石英或玻璃基板组成。光掩膜版涂有不透明薄膜。更复杂的掩模版使用其他材料。 一般来说&#xff0c;术语“photo mask”用于描述与 1X 步进机或光刻系统一起使用的“主模板”。…

希尔排序原理

目录&#xff1a; 一、希尔排序与插入排序 1&#xff09;希尔排序的概念 2&#xff09;插入排序实现 二、希尔排序实现 一、希尔排序与插入排序 1&#xff09;希尔排序的概念 希尔排序(Shells Sort)是插入排序的一种又称“缩小增量排序”&#xff08;Diminishing Incremen…

ElasticSearch7.x - HTTP 操作 - 索引操作

创建索引 对比关系型数据库,创建索引就等同于创建数据库 在 Postman 中,向 ES 服务器发 PUT 请求 :http://192.168.254.101:9200/shopping 说明 {"acknowledged"【响应结果】: true, # true 操作成功"shards_acknowledged"【分片结果】: true, # 分片操…

紧急事件,停电导致安森美韩国厂全线停工 | 百能云芯

11月9日的消息报道&#xff0c;全球半导体公司安森美遭遇了一场意外的停电事故&#xff0c;发生在位于韩国的富川晶圆厂&#xff0c;导致整个工厂陷入停工状态&#xff01; 停电事件发生在11月5日&#xff0c;导致富川晶圆厂的产线暂时停工&#xff0c;停电持续了大约20分钟。由…

Mac电脑Visio文件编辑查看软件推荐Visio Viewer for Mac

mac版Visio Viewer功能特色 在Mac OS X上查看Visio绘图和图表 在Mac OS X上轻松查看MS Visio文件 在Mac上快速方便地打开并阅读Visio文件&#xff08;.vsd&#xff0c;.vsdx&#xff09;。 支持通过放大&#xff0c;缩小&#xff0c;旋转&#xff0c;文本选择和复制&#xff0…

DSP开发例程(4): logbuf_print_to_uart

目录 DSP开发例程: logbuf_print_to_uart新建工程源码编辑app.cfgos.cmain.c 调试说明 DSP开发例程: logbuf_print_to_uart SYS/BIOS 提供了 xdc.runtime.Log, xdc.runtime.LoggerBuf 和 xdc.runtime.LoggerSys 这几个模块用于日志记录. 日志信息在 应用程序调试和状态监控中非…

第二十九章 目标检测中的测试模型评价指标(车道线感知)

前言 近期参与到了手写AI的车道线检测的学习中去&#xff0c;以此系列笔记记录学习与思考的全过程。车道线检测系列会持续更新&#xff0c;力求完整精炼&#xff0c;引人启示。所需前期知识&#xff0c;可以结合手写AI进行系统的学习。 介绍 自动驾驶的一大前提是保证人的安全…

中国智能驾驶的“突围赛”打响,这家本土厂商为何能成为“先行者”?

中国本土厂商正在成为全球智能汽车产业链的“核心力量”。 根据《高工智能汽车研究院》数据显示&#xff0c;今年1-6月&#xff0c;自主品牌标配L2&#xff08;含L2&#xff09;级辅助驾驶交付新车155.34万辆。其中&#xff0c;搭载中国本土智能驾驶解决方案提供商&#xff08…

Nacos使用指南

Nacos使用指南 1.认识Nacos Nacos是SpringCloudAlibaba的一个组件&#xff0c;遵循SpringCloud规范 2.Nacos的优势 1.支持服务端主动检测服务提供者状态。临时实例采用心跳检测&#xff0c;非临时实例采用主动检测 2.Nacos支持服务列表变更消息推送&#xff0c;消息更加及…

C++入门篇3(类和对象【重点】)

文章目录 C入门篇3&#xff08;类和对象【重点】&#xff09;1、面向过程和面向对象2、类的引入3、类的定义4、类的访问限定符及封装4.1、访问限定符4.2、封装 5、类的作用域6、类的实例化&#xff08;对象&#xff09;7、类对象模型7.1、类对象的存储方式7.2、结构体&#xff…

mysql索引下推

文章目录 什么是索引下推索引下推优化的原理索引下推的具体实践没有使用ICP使用ICP 总结索引下推使用条件相关系统参数 什么是索引下推 索引下推(Index Condition Pushdown&#xff0c;简称ICP)&#xff0c;是MySQL5.6版本的新特性&#xff0c;它能减少回表查询次数&#xff0…

【Proteus仿真】【51单片机】汽车尾灯控制设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用按键、LED模块等。 主要功能&#xff1a; 系统运行后&#xff0c;系统运行后&#xff0c;系统开始运行&#xff0c;K1键控制左转向灯&#xff1b;…

C# .NET Core API 注入Swagger

C# .NET Core API 注入Swagger 环境 Windows 10Visual Studio 2019(2017就有可以集中发布到publish目录的功能了吧)C#.NET Core 可跨平台发布代码,超级奈斯NuGet 套件管理dll将方法封装(据说可以提高效率,就像是我们用的dll那种感觉)Swagger 让接口可视化编写时间2020-12-09 …

MySQL on duplicate key update用法

基本使用方法 public static final String SQL_TQI_SINK "insert into " ConfigureContext.get(ConfigKeyConstants.MYSQL_TABLE_TQI) " \n" "(mile_km, mile_start_km, mile_start_m, is_out, tqi_alig_l, \n" "tqi_alig_r, tqi_surf_l…

c语言刷题第10周(16~20)

规律&#xff1a; 若多个次数最多按ASCII码顺序输出。 用for循环i取&#xff08;0~26&#xff09; 则输出满足条件的字符串中位置最靠前的那个。 用while循环遍历&#xff08;while&#xff08;a[i]!\0&#xff09;&#xff09; 从键盘输入任意只含有大小写字母的串s&…

22款奔驰S400L升级原厂360全景影像 打破死角

本次星骏汇小许介绍的是22款奔驰S400L升级原厂360全景影像&#xff0c;上帝视角看清车辆周围环境&#xff0c;更轻松驾驶 升级360全景影像系统共有前后左右4个摄像头&#xff0c;分别在车头&#xff0c;车尾&#xff0c;以及两边反光镜下各一个&#xff0c;分别用来采集车头&a…

手写C++ 实现链表的反转、删除、合并

目录 一、手写List成员方法 1.1 打印链表 1.2 删除链表节点 1.3 链表中倒数第k个节点 1.4 反转链表 1.5 合并两个排序链表 二、完整代码 一、C实现链表成员方法 在上一篇博客《手写链表C》&#xff0c;实现了基本的List类。在面试中&#xff0c;经常被问到List如何反转、…

视频集中存储EasyCVR平台播放一段时间后出现黑屏是什么原因?该如何解决?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

jsvascript使用dhtmlXTreeObject的loadJSONObject绘制目录树

文章目录 1&#xff0c;引入dhtmlXTreeObject的css和js文件2&#xff0c;创建一棵目录树2.1&#xff0c;let tree new dhtmlXTreeObject(id-dhtmltree-0, "100%", "100%", 0);2.2&#xff0c;设置图片根目录&#xff08;后续使用到的图片都是相对于该目录…