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

news2024/11/26 15:49:51

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

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

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

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.coloradmin.cn/o/1160921.html

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

相关文章

车载网络测试 - UDS诊断篇 - CAN与OSI七层模型

目录 为什么会介绍OSI七层模型&#xff1f; CAN规范与OSI模型 1、Physical Layer 1 2、Data Link Layer 2 3、Network Layer 3 & Transport Protocol Layer 4 4、Transport Protocol Layer 4 5、Session Layer 5 & Presentation Layer 6 & Application Laye…

【c++Leetcode】287. Find the Duplicate Number

问题入口 思想&#xff1a;Floyds Tortoise and Hare 这个算法除了可以检测是否有环&#xff08;问题入口&#xff09;&#xff0c;还可以用来检测重复数。当然这还需要一个慢指针才能实现。具体请点击标题跳转到原视频&#xff0c;这里是把内容再梳理一遍。如果有不对的地方…

多路转接之epoll

本篇博客介绍&#xff1a; 多路转接之epoll 多路转接之epoll 初识epollepoll相关系统调用epoll的工作原理epoll服务器编写成员变量构造函数 循环函数HandlerEvent函数epoll的优缺点 我们学习epoll分为四部分 快速理解部分概念 快速的看一下部分接口讲解epoll的工作原理手写epo…

Springboot 集成 Seata

Seata 是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式&#xff0c;为用户打造一站式的分布式解决方案。Seata官网 1.找到适合的Seata版本 参考&#xff1a;SpringCloudAlibaba S…

译文:我们如何使 Elasticsearch 7.11 中的 date_histogram 聚合比以往更快

这篇文章是ES7.11版本的文章&#xff0c;主要学习的是思路&#xff0c;记录在这里留作以后参考用。 原文地址&#xff1a;https://www.elastic.co/cn/blog/how-we-made-date-histogram-aggregations-faster-than-ever-in-elasticsearch-7-11 正文开始&#xff1a; Elasticsea…

美国Embarcadero产品经理Marco Cantù谈Delphi/C++ Builder目前开发应用领域

美国Embarcadero产品经理Marco Cant 日前在欧洲的一次信息技术会议上谈到了Delphi/C Builder目前开发应用领域&#xff1a;RAD Studio Delphi/C Builder目前应用于哪些开发领域&#xff1f;使用 Delphi 和 CBuilder 进行开发为当今众多企业提供了动力。 航空航天 大型数据采集 …

4.2 final关键字

思维导图&#xff1a; 4.2.1 final关键字修饰类 定义和基本概念&#xff1a; 在 Java 中&#xff0c;final关键字有“最终”或“不可改”的含义。使用final关键字修饰的元素&#xff08;类、方法或变量&#xff09;都有其特定的特性。 主要应用和注意事项&#xff1a; 修饰类&…

Spring - 手写模拟Spring底层原理

手写Spring 定义配置类AppConfig ComponentScan("com.spring.zsj") public class AppConfig {Beanpublic ApplicationListener applicationListener() {return new ApplicationListener() {Overridepublic void onApplicationEvent(ApplicationEvent event) {System…

yolov7模型轻量化改进之MobileOne骨干替换

本文在之前文章yolov7分割训练的基础上进行改进: https://blog.csdn.net/qq_41920323/article/details/129464115?spm=1001.2014.3001.5502 具体GitHub工程下载,环境安装配置,数据准备等,请借鉴之前的文章,此处只介绍如何进行改进。 MobileOne地址:https://github.com…

【算法|滑动窗口No.3】leetcode3. 无重复字符的最长子串

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

Nignx安装负载均衡动静分离以及Linux前端项目部署将域名映射到特定IP地址

目录 一、nginx简介 1.1 定义 1.2 背景 1.3 作用 二、nginx搭载负载均衡提供前后分离后台接口数据 2.1 nginx安装 2.1.1 下载依赖 2.1.2 下载并解压安装包 2.1.3 安装nginx 2.1.4 启动nginx服务 2.2 tomcat负载均衡 2.2.1 负载均衡所需服务器准备 2.2.2 配置修改 …

内网穿透入门

内网穿透 内网穿透&#xff08;英文&#xff1a;Port Forwarding&#xff09;是一种网络技术&#xff0c;用于将公共互联网&#xff08;外网&#xff09;的请求转发到私有局域网&#xff08;内网&#xff09;中的特定设备或服务。在许多情况下&#xff0c;设备或服务位于一个局…

负载均衡深度解析:算法、策略与Nginx实践

引言 如今&#xff0c;网站和应用服务面临着巨大的访问流量&#xff0c;如何高效、稳定地处理这些流量成为了一个亟待解决的问题。负载均衡技术因此应运而生&#xff0c;它通过将流量合理分配到多个服务器上&#xff0c;不仅优化了资源的利用率&#xff0c;还大大提升了系统的…

下载树莓派对应的64位Ubuntu系统步骤

说点废话&#xff1a;因为ros2需要安装在64位Ubuntu上面&#xff0c;所以安装64位最合适&#xff1b; 第一步打开https://cn.ubuntu.com/ 网站&#xff1b;选择下载--->iot----> 选择这个镜像文件下载。我觉得镜像文件是img格式的&#xff0c;跟iso文件区别是&#xff…

牛客网刷题-(9)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

VisualSVN initialization failed, For more details see Output window.

VisualSVN initialization failed, For more details see Output window. 通过输出窗口查看详细日志地址&#xff1a; 打开日志&#xff0c;发现报错信息为&#xff1a;Cannot get image ‘742477e2-c767-429f-b906-6c553b7cd1d1:12, 9x16’ from the image service. 原因&a…

Java17-20新特性

目录 一、Java17新特性 1、switch语法的变化(预览) 2、Sealed Classes 3、伪随机数的变化 4、去除了AOT和JIT 二、Java18新特性 1、默认使用UTF-8字符编码 2、简单的web服务器 3、将被移除的方法 4、snippet注解 三、Java19新特性 1、Virtual Threads(Preview)虚拟…

vue图书馆书目推荐数据分析与可视化-计算机毕业设计python-django-php

建立本图书馆书目推荐数据分析是为了通过系统对图书数据根据算法进行的分析好推荐&#xff0c;以方便用户对自己所需图书信息的查询&#xff0c;根据不同的算法机制推荐给不同用户不同的图书&#xff0c;用户便可以从系统中获得图书信息信息。 对用户相关数据进行分析&#xff…

Flutter 05 组件状态、生命周期、数据传递(共享)、Key

一、Android界面渲染流程UI树与FlutterUI树的设计思路对比 二、Widget组件生命周期详解 1、Widget组件生命周期 和其他的视图框架比如android的Activity一样&#xff0c;flutter中的视图Widget也存在生命周期&#xff0c;生命周期的回调函数体现在了State上面。组件State的生命…

python自动化测试(九):EcShop添加商品功能

前置条件&#xff1a; 本地部署&#xff1a;ECShop的版本是3.0.0、Google版本是 Google Chrome65.0.3325.162 (正式版本) &#xff08;32 位&#xff09; py的selenium版本是3.11.0 目录 一、前置代码 二、添加商品操作 2.1 点击添加商品 2.2 添加名称、分类、品牌 2…