【数据结构与算法】排序二叉树的创建节点的添加和删除(附代码实现与代码讲解)

首先来了解下排序二叉树的基本概念

排序二叉树:任意一个根节点,比他的左子树中的任意节点都大,比他的右子树中的任意节点都小

比如下面的这个树就是排序二叉树

OK,在了解了这个基本概念之后,就可以去看下面的代码了

#include<iostream>
#include<stdlib.h>
using namespace std;//树的节点结构体
typedef struct node
{int value;struct node* left;//左孩子struct node* right;//右孩子
}Binary_Tree;//向排序二叉树中添加节点
void Add_Node(Binary_Tree** tree, int num)
{//创建一个临时节点,申请空间并进行初始化Binary_Tree* temp = NULL;temp = (Binary_Tree*)malloc(sizeof(Binary_Tree));temp->value = num;temp->left = NULL;temp->right = NULL;//如果该排序二叉树的根节点为空if (*tree == NULL){*tree = temp;return;}Binary_Tree* pnode = *tree;while (pnode){//如果要插入的值小于该结点的数值,应放入左子树中if (pnode->value > num){//如果该结点左孩子为空if (pnode->left == NULL){pnode->left = temp;return;}//如果该结点左孩子不为空,就需要往左子树的更深处去找else{pnode = pnode->left;}}//如果要插入的值小于该结点的数值,应放入右子树中else if (pnode->value < num){//如果该结点右孩子为空if (pnode->right == NULL){pnode->right = temp;return;}//如果该结点右孩子不为空,就需要往右子树的更深处去找else{pnode = pnode->right;}}else{cout << "输入的数据与树中的节点数据存在重复,请重新输入" << endl;free(temp);temp = NULL;return;}}
}//建立无重复数值的排序二叉树
Binary_Tree* BST_Create()
{int num;//节点数值int size;//节点个数int i;Binary_Tree* tree = NULL;cout << "请输入排序二叉树中结点的个数 :";cin >> size;cout << "请依次输入节点中的数据 :" << endl;for (i = 0; i < size; i++){cin >> num;//向树中添加节点到正确的位置Add_Node(&tree, num);}cout << "排序二叉树初始化完成" << endl;return tree;
}//在排序二叉树中搜索与目标数值对应的结点
void Search_AimNode(Binary_Tree* tree, int aim_num, Binary_Tree** del_node, Binary_Tree** father)
{while (tree){if (tree->value == aim_num){*del_node = tree;return;}//如果目标数小于该节点的数值,说明要再往左子树里去找else if (tree->value > aim_num){*father = tree;tree = tree->left;}//如果大于,要往右子树去找else if (tree->value < aim_num){*father = tree;tree = tree->right;}}*father = NULL;cout << "该排序二叉树中没有与目标数值对应的节点" << endl;
}//排序二叉树将与aim_num数值对应的节点删除
void Node_Delete(Binary_Tree** tree , int aim_num)
{//在查找的过程中,有一点需要注意:我们要定义一个变量,来接取该结点的根节点//这样做的目的是如果查找的这个结点就是我们要找的目标结点的话,在该结点删除后,能够重新连接到该结点的根节点上,以建立新的排序二叉树Binary_Tree* del_node = NULL;Binary_Tree* father = NULL;//查找该树中是否有与目标数值对应的节点Search_AimNode(*tree, aim_num, &del_node, &father);//如果没有找到对应的节点,就直接退出if (del_node == NULL){return;}//如果找到了对应的节点,就要考虑以下三种情况:/*1.这个结点没有孩子,那么直接删除这个结点就可以了2.如果这个结点只有一个孩子,只需要将这个结点的孩子结点与根节点进行链接就可以了3.如果这个结点有两个孩子,这个情况有两种解决办法——①.用左子树的最大值来替代,也就是左子树的最右端结点,然后删除左子树的这个节点  ②.右子树的最小值来替代,也就是右子树的最左端结点,然后删除右子树的这个节点为什么会有这两种解决办法呢? 这就牵涉到BST的基本概念了——任意一个父亲节点,都比他的左子树大,都比他的右子树小所以如果对这个结点进行修改的话,我们希望在该树中找到一个一个最接近该结点大小的数值来替代他,而在排序二叉树中左子树的最大值和右子树的最小值就是最接近这个结点大小的数值*///一、2个孩子Binary_Tree* mark = NULL;if ((del_node->left != NULL) && (del_node->right != NULL)){mark = del_node;//找左子树的最右侧节点//先进入该结点的左子树father = del_node;del_node = del_node->left;//找该左子树的最右侧结点while (del_node->right != NULL){father = del_node;del_node = del_node->right;}mark->value = del_node->value;}//二、1个孩子或0个孩子//这个地方需要做一个特殊处理,如果要换的结点是根节点的话,father就是NULL,要做一下特殊判断if (father == NULL){//看这个孩子是左孩子还是右孩子//这个地方要为大家讲解一下,否则有些同学可能不太懂为什么这个地方0个孩子的情况也适用/*1.当左孩子不为空,右孩子为空——根节点变成当前节点的左孩子2.当左孩子为空,右孩子不为空——根节点变成当前节点的右孩子3.当左孩子、右孩子都为空时——根节点变成当前节点的右孩子,但右孩子为空,所以根节点也为空*/*tree = del_node->left ? del_node->left : del_node->right;free(del_node);del_node = NULL;return;}//如果要删除的节点不是根节点else{//如果这个结点是其根节点的左孩子if (del_node == father->left){father->left = del_node->left ? del_node->left : del_node->right;}//如果这个结点是其根节点的右孩子if (del_node == father->right){father->right = del_node->left ? del_node->left : del_node->right;}free(del_node);del_node = NULL;return;}
}//中序遍历
void Inorder_Traversal(Binary_Tree* pTree)
{//左、根、右if (pTree == NULL){return;}//左子树Inorder_Traversal(pTree->left);//节点打印,也就是打印根节点的数据cout << pTree->value << " ";//右子树Inorder_Traversal(pTree->right);
}int main()
{Binary_Tree* tree = NULL;tree = BST_Create();cout << "中序遍历的结果为:";Inorder_Traversal(tree);cout << endl;int aim_num;cout << "请输入你想要删除的的目标数据 : ";cin >> aim_num;Node_Delete(&tree, aim_num);cout << "该树的中序遍历结果为 : ";Inorder_Traversal(tree);return 0;
}

以上就是本篇博客的全部内容了,大家有什么地方没有看懂的话,可以在评论区留言给我,咱要力所能及的话就帮大家解答解答

今天的学习记录到此结束啦,咱们下篇文章见,ByeBye!

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

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

相关文章

【Linux】关于Nginx的详细使用,部署项目

前言&#xff1a; 今天小编给大家带来的是关于Nginx的详细使用&#xff0c;部署项目&#xff0c;希望可以给正在学习&#xff0c;工作的你带来有效的帮助&#xff01; 一&#xff0c;Nginx简介 Nginx是一个高性能的开源Web服务器和反向代理服务器。它最初由Igor Sysoev在2004年…

Linux开机、重启、关机和用户登录注销

1.【关机】 shutdown shutdown now 表示立即关机 shutdown -h now 表示立即关机 shutdown -h 1 表示1分钟后关机 halt 用来关闭正在运行的Linux操作系统 2.【重启】 shutdown -r now 表示立即重启 reboot 重启系统 sync …

Spring - 提供 IOC 容器实现的两种方式

BeanFactory&#xff1a; BeanFactory是Spring的IOC容器的基本实现&#xff0c;它是一个接口&#xff0c;提供了IOC容器的基本功能。BeanFactory在加载配置文件时不会立即创建对象&#xff0c;而是在需要时&#xff08;延迟初始化&#xff09;才会创建对象。通常BeanFactory在S…

OceanBase:01-单机部署(开发环境)

目录 一、体系架构 二、配置要求 三、解压安装包 四、执行安装 五、配置环境变量 六、快速部署 七、访问数据库 OceanBase 数据库&#xff08;OceanBase Database&#xff09;是一款蚂蚁集团完全自研的企业级原生分布式数据库&#xff0c;在普通硬件上实现金融级高可用&…

前端实验(一)单页面应用的创建

实验目的 掌握使用vite创建vue3单页面程序命令熟悉所创建程序的组织结构熟悉单页面程序运行原理能够编写简单的单页面程序 实验内容 创建一个名为vue-demo的单页面程序编写简单的单页面程序页面运行单页面程序 实验步骤 使用vite创建单页面程序 创建项目名为目录vue-demo的…

Linux入门指令和权限讲解

目录 一&#xff0c;Linux指令讲解 1. ls 指令&#xff08;查看文件&#xff09; 2. pwd命令&#xff08;展现当前工作目录&#xff09; 3. cd 指令&#xff08;改变当前所处工作目录&#xff09; 4. touch指令&#xff08;创建文件&#xff09; 5.mkdir指令&#xff08;创…

Java日志组件介绍之二

一、前言 Java日志组件介绍之一 主要介绍了JDK内置日志和Apache的common-logging通用日志接口&#xff0c;今天这篇我们继续了解Java其它一些日志组件。 二、slf4j slf4j即Simple Logging Facade for JAVA &#xff0c;简单日志门面&#xff0c;类似common-logging&#xff0…

Verilog:写流水灯时遇到的问题

module flow_led(input sys_clk, //系统时钟50Mhz 周期0.02nsinput sys_rst_n, //系统异步复位&#xff0c;低电平有效output reg [3:0] led ); reg [24:0] cnt;//计数器计时0.5s250000000*0.02ns always(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)cnt <…

2023最新ChatGPT商业运营系统源码+支持GPT4/支持ai绘画+支持Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

Mac上的iTerm2和Oh My Zsh 的安装(安装过程和失败详解)

前言&#xff08;无重点&#xff0c;安装往后看&#xff09; 由于在很多人的安利下&#xff0c;说很好用&#xff0c;作者今天花费了4个小时用血的教训总结出来的安装教程&#xff0c;我在安装过程中遇到的最大的问题就是 1. curl: (7) Failed to connect to raw.githubusercon…

由QTableView/QTableWidget显示进度条和按钮,理解qt代理delegate用法

背景&#xff1a; 我的最初应用场景&#xff0c;就是要在表格上用进度条显示数据&#xff0c;以及放一个按钮。 qt-creator中有自带的delegate示例可以参考&#xff0c;但终归自己动手还是需要理解细节&#xff0c;否则不能随心所欲。 自认没那个天赋&#xff0c;于是记录下…

判断一个数字是否是奇数

思路&#xff1a; 用scanf读取一个数字num后&#xff0c;如果它不能被2整除&#xff0c;那么它是奇数&#xff0c;否则就是偶数。 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> //引用头文件 int main() {int num;printf("请输入一个数字 &#xff1a;&qu…

正向代理和反向代理与负载均衡

自存用 什么是反向代理&#xff0c;反向代理与正向代理的区别 一文帮你梳理清楚「正向代理和反向代理的区别与联系」 什么是反向代理服务器 正向代理为用户服务&#xff0c;给用户换个ip使其能访问其他网站 反向代理为服务器服务&#xff0c;使用户访问特定网站服务器。反向代…

JAVA 实现PDF转图片(spire.pdf.free版)

1.引入jar包 导入方法1&#xff1a; 手动引入。将Free Spire.PDF for Java下载到本地&#xff0c;解压&#xff0c;找到lib文件夹下的Spire.PDF.jar文件。在IDEA中打开如下界面&#xff0c;将本地路径中的jar文件引入Java程序&#xff1a; 导入方法2&#xff1a;如果您想通过…

Java设计模式之命令模式

目录 定义 结构 案例 优点 缺点 使用场景 JDK源码解析 Thread中start与run方法的区别 定义 将一个请求封装为一个对象&#xff0c;使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通&#xff0c;这样方便将命令对象进行存储、传递、调用、增…

Java调用HTTPS接口,绕过SSL认证

1&#xff1a;说明 网络编程中&#xff0c;HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是一种通过加密的方式在计算机网络上进行安全通信的协议。网络传输协议&#xff0c;跟http相比更安全&#xff0c;因为他加上了SSL/TLS协议来加密通信内容。 Java调…

Thinkphp6项目在虚拟机无法指向pulic的目录访问的方法

以阿里云虚拟主机为例&#xff0c;服务器环境为 LAMP&#xff0c;Apache2.4 php7.2 mysql5.7 1.根目录新建 index.php 文件&#xff0c;将以下内容放入文件中 <?php include ./public/index.php;2.将 public 目录下的 admin.php、backend 文件夹、static 文件夹、tinymc…

Linux--线程--互斥锁

1.互斥量 a&#xff09;互斥量&#xff08;mutex&#xff09;从本质上来说是一把锁&#xff0c;一般在主线程中定义一个互斥量&#xff0c;就是定义一把锁。然后根据我们的需求来对线程操作这把锁。 b&#xff09;如果给所有的线程都加上锁了&#xff0c;线程们会去争取内存空…

Python 中的 Schedule

本篇文章将介绍 Python 中的 Schedule 包&#xff0c;以在特定时间间隔后定期安排作业。 Schedule是Python中的一个轻量级进程调度程序库&#xff0c;用于安排任务以指定的时间间隔定期运行。 我们可以使用人类友好的语法调用函数或任何可调用对象来自动执行任务&#xff0c;…

基于深度学习的语音识别算法的设计与实现

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、课题内容二、需求分析2.1 算法需求分析2.2 语音录制2.3 声学模型2.4 语言模型2.5 训练集和测试集2.6 深度神经网络 三 算法设计原理3.1 语音识别系统3.1.1 声学模型3.1.2 语言模型3.1.3 发音词典 四 简单问答…