【数据结构】删除二叉树中的结点;树与二叉树的相互转换(含二叉树/二叉排序树的基本运算)

news2024/9/24 5:29:08

定义二叉树结点和树结点结构体: 

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int BTDataType;
typedef int TDataType;

//二叉树
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
}BTNode;

//树
typedef struct TreeNode
{
	struct TreeNode* leftchild; //左孩子
	struct TreeNode* rightbrother; //右兄弟
	TDataType data;
}TNode;

 

一.删除二叉树中的结点

1.思想:

(1)首先判断要删除的结点是否存在,如果不存在则直接返回 NULL。
(2)如果要删除的结点小于当前结点,则递归删除左子树中的结点。
(3)如果要删除的结点大于当前结点,则递归删除右子树中的结点。
(4)如果要删除的结点等于当前结点,则分四种情况进行处理:
情况1:要删除的结点是叶子结点,直接删除即可。
情况2:要删除的结点只有右子树,将右子树替换当前结点即可。
情况3:要删除的结点只有左子树,将左子树替换当前结点即可。
情况4:要删除的结点既有左子树又有右子树,将右子树中的最小值替换当前结点即可。
最后返回删除结点后的二叉排序树的根节点。

2.代码实现

//查找二叉排序树中的最小值结点
BTNode* FindMin(BTNode* root) 
{
	if (root == NULL) 
	{
		return NULL;
	}
	else if (root->left == NULL) 
	{
		return root;
	}
	else 
	{
		return FindMin(root->left);
	}
}


//二叉树删除结点
BTNode* DeleteBTNode(BTNode* root, BTDataType data)
{
	//查找该结点
	if (root == NULL) 
	{
		return NULL;
	}
	else if (data < root->data)
	{
		root->left = DeleteBTNode(root->left, data);
	}
	else if (data > root->data) 
	{
		root->right = DeleteBTNode(root->right, data);
	}
	else 
	{
		//找到要删除的结点
		if (root->left == NULL && root->right == NULL) 
		{
			//情况1:要删除的结点是叶子结点
			free(root);
			root = NULL;
		}
		else if (root->left == NULL) 
		{
			//情况2:要删除的结点只有右子树
			BTNode* temp = root;
			root = root->right;
			free(temp);
		}
		else if (root->right == NULL) 
		{
			//情况3:要删除的结点只有左子树
			BTNode* temp = root;
			root = root->left;
			free(temp);
		}
		else 
		{
			//情况4:要删除的结点既有左子树又有右子树
			BTNode* temp = FindMin(root->right);
			root->data = temp->data;
			root->right = DeleteBTNode(root->right, temp->data);
		}
	}
	return root;
}

二.实现树与二叉树的相互转换

二叉树转换成树:

将二叉树的左孩子变成树的左孩子

将二叉树的右孩子变成树的右兄弟

树转换成二叉树:

将树的左孩子变成二叉树的左孩子,

将树的右兄弟变成二叉树的右孩子

//二叉树转换成树
TNode* ExchangeToTree(BTNode* root)
{
	if (root == NULL)
	{
		return NULL;
	}
	else
	{
		TNode* troot = (TNode*)malloc(sizeof(TNode));
		troot->data = root->data;
		troot->leftchild = ExchangeToTree(root->left);
		troot->rightbrother = ExchangeToTree(root->right);
		return troot;
	}
}

//树转换成二叉树
TNode* ExchangeToBinaryTree(TNode* troot)
{
	if (troot == NULL)
	{
		return NULL;
	}
	else
	{
		BTNode* root = (BTNode*)malloc(sizeof(BTNode));
		root->data = troot->data;
		root->left = ExchangeToBinaryTree(troot->leftchild);
		root->right = ExchangeToBinaryTree(troot->rightbrother);

		return root;
	}

}

三.实现二叉树/二叉排序树基本运算

//二叉排序树
//初始化
void InitBinaryTree(BTNode** root)
{
	*root = NULL;
}

//二叉排序树插入结点
void CreateBinaryTree(BTNode** root, BTDataType x)
{
	//走到空结点,即插入
	if ((*root) == NULL)
	{
		(*root) = (BTNode*)malloc(sizeof(BTNode));
		(*root)->data = x;
		(*root)->left = NULL;
		(*root)->right = NULL;
		return;
	}

	//已有该数据,即返回
	if (x == (*root)->data)
	{
		printf("已有该数据\n");
		return;
	}
	//小于该结点的数据,则往左走
	else if(x < (*root)->data)
	{
		CreateBinaryTree(&((*root)->left), x);
	}
	//大于该结点的数据,则往右走
	else 
	{
		CreateBinaryTree(&((*root)->right), x);
	}
}

//二叉排序树关键字key的查找长度
int FindBinaryTree(BTNode* root, BTDataType key)
{
	//走到空,返回
	if (root == NULL)
	{
		return;
	}
	//查找到key,则计数+1
	if (root->data == key)
	{
		return 1;
	}
	//递归查找
	if (key < root->data)
	{
		return FindBinaryTree(root->left, key) + 1;
	}
	if (key > root->data)
	{
		return FindBinaryTree(root->right, key) + 1;
	}
}

//二叉排序树中,打印a,b两个结点的公共祖先
BTNode* PublicAncestors(BTNode* root, BTDataType a, BTDataType b)
{
	if (root == NULL)
	{
		return NULL;
	}
	//a,b都在root的左子树
	if (a < root->data && b < root->data)
	{
		return PublicAncestors(root->left, a, b);
	}
	//a,b都在root的右子树
	if (a > root->data && b > root->data)
	{
		return PublicAncestors(root->right, a, b);
	}
	//a,b分别在root的左右子树,说明root就是a,b的祖先结点
	else
	{
		return root;
	}
}

//二叉树前序遍历
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

//二叉树中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

//二叉树后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}


//二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	//结点为空则返回0,否则返回结点的左子树结点个数+结点的右子树结点个数+1(结点本身是1个)
	return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

//二叉树叶子结点的个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	//是叶子结点则返回1,否则返回结点的左子树的叶子结点个数+结点的右子树的叶子结点个数
	return (root->left == NULL && root->right == NULL) ? 1 : 
		BinaryTreeLeafSize(root->left)
		+ BinaryTreeLeafSize(root->right);
}

//二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)
	{
		return 1;
	}
	
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
	
}

//二叉树深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDepth = BinaryTreeDepth(root->left);
	int rightDepth = BinaryTreeDepth(root->right);

	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

//二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}

	if (root->data == x)
	{
		return root;
	}

	BTNode* leftRet = BinaryTreeFind(root->left, x);
	if (leftRet)
	{
		return leftRet;
	}
	BTNode* rightRet = BinaryTreeFind(root->right, x);
	if (rightRet)
	{
		return rightRet;
	}

	return NULL;
}


//计算二叉树的最大宽度
int BinaryTreeWidthMax(BTNode* root)
{
	assert(root);
	//记录二叉树的深度
	int depth = BinaryTreeDepth(root);
	int i = 1;
	int max = 1;
	while (i <= depth)
	{
		//复用接口,tmp 为每层的结点数
		int tmp = BinaryTreeLevelKSize(root, i);
		if (tmp > max)
		{
			max = tmp;
		}
		i++;
	}
	return max;
}

//二叉树与树的相互转换
//二叉树转换成树
TNode* ExchangeToTree(BTNode* root)
{
	if (root == NULL)
	{
		return NULL;
	}
	else
	{
		TNode* troot = (TNode*)malloc(sizeof(TNode));
		troot->data = root->data;
		troot->leftchild = ExchangeToTree(root->left);
		troot->rightbrother = ExchangeToTree(root->right);
		return troot;
	}
}

//树转换成二叉树
TNode* ExchangeToBinaryTree(TNode* troot)
{
	if (troot == NULL)
	{
		return NULL;
	}
	else
	{
		BTNode* root = (BTNode*)malloc(sizeof(BTNode));
		root->data = troot->data;
		root->left = ExchangeToBinaryTree(troot->leftchild);
		root->right = ExchangeToBinaryTree(troot->rightbrother);

		return root;
	}

}

//打印树
void ShowTree(TNode* troot)
{
	TNode* child = troot->leftchild;
	int flag = 1; //设置标记
	while (flag)
	{
		flag = 0;
		while (troot)
		{
			printf("%d ", troot->data);
			if (troot->leftchild)
			{
				flag = 1;
				child = troot->leftchild; //标记下一层的第一个结点
				//若没有下一层结点,则flag为0,退出循环
			}
			troot = troot->rightbrother;
		}
		printf("\n");
		troot = child;
	}
	printf("\n");
}

//查找二叉排序树中的最小值结点
BTNode* FindMin(BTNode* root) 
{
	if (root == NULL) 
	{
		return NULL;
	}
	else if (root->left == NULL) 
	{
		return root;
	}
	else 
	{
		return FindMin(root->left);
	}
}

// 销毁二叉树,释放空间
void DestroyBTree(BTNode* root) 
{
	if (root == NULL) 
	{
		return;
	}
	DestroyBTree(root->left);
	DestroyBTree(root->right);
	free(root);
}

四.测试

 1.代码

int main()
{
	BTNode* root = NULL;

	//插入结点
	CreateBinaryTree(&root, 9);
	CreateBinaryTree(&root, 5);
	CreateBinaryTree(&root, 7);
	CreateBinaryTree(&root, 8);
	CreateBinaryTree(&root, 6);
	CreateBinaryTree(&root, 4);

	二叉树节点个数
	printf("二叉树的结点个数:%d\n", BinaryTreeSize(root));

	//二叉树的最大宽度
	printf("二叉树的最大宽度:%d\n", BinaryTreeWidthMax(root));

	//二叉树叶子结点的个数
	printf("二叉树叶子结点的个数:%d\n", BinaryTreeLeafSize(root));

	//二叉树第k层节点个数
	printf("二叉树第k层节点个数:%d\n\n", BinaryTreeLevelKSize(root, 3));

	//前、中、后序遍历
	printf("二叉树的前序遍历:");
	PreOrder(root);
	printf("\n中序遍历:");
	InOrder(root);
	printf("\n后序遍历:");
	PostOrder(root);
	printf("\n");
	printf("\n");

	//寻找两个结点的公共祖先
	BTNode* node = PublicAncestors(root, 6, 8);
	printf("5和11两个结点的公共祖先:%d\n ", node->data);

	//二叉排序树关键字5的查找长度
	int lenth = FindBinaryTree(root, 5);
	printf("二叉排序树关键字5的查找长度:%d\n\n ", lenth);

	//删除数据为5的结点
	root = DeleteBTNode(root, 5);
	printf("删除数据为5的结点之后的中序遍历:");
	InOrder(root);
	printf("\n");

	//二叉树转换成树
	TNode* troot = ExchangeToTree(root);
	printf("二叉树转换成树:\n");
	ShowTree(troot);
	printf("\n");

	//树转换成二叉树
	BTNode* tmproot = ExchangeToBinaryTree(troot);
	printf("树转换成二叉树(中序遍历):\n");
	InOrder(tmproot);
	printf("\n");
	DestroyBTree(tmproot);

	DestroyBTree(root);
	return 0;
}

2.运行结果

 

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

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

相关文章

python requests一个非常蠢的问题: post请求中data和json的区别

问题 最近在写java的ODD cucumber的框架&#xff0c;其中的接口调用相比python来说非常繁琐&#xff0c;很不友好&#xff0c;如下图 所以我打算先用python调一下这个接口,代码如下&#xff0c;url已做脱敏处理 import requests url "http://xxxxxxxxxxxxxxxxxxx:966…

嵌入式安卓开发:使用Camera2获取相机

文章目录 Camera2介绍Camera2的主要API类介绍CameraManager通过CameraManage获取Cameracharacteristics通过CameraManage获取CameraDevice从CameraDevice获取CameraCaptureSession预览效果 参考 Camera2介绍 从Android 5.0开始&#xff0c;Google 引入了一套全新的相机框架 Ca…

银行数字化转型导师坚鹏:银行数字化转型培训方案

目录 一、银行数字化转型培训背景 二、银行数字化转型模型 三、银行数字化转型课程设计思路 四、 银行数字化转型课程基本介绍 五、 银行数字化转型课程设置 六、银行数字化转型课程大纲 七、培训方案实施流程 一、银行数字化转型培训背景 2020年1月3日&#xff…

2023年IC行业薪资有多高?(内含各岗位薪资对比)

在网上看到一个很火的提问&#xff1a;2023了&#xff0c;IC行业高薪还在吗&#xff1f;其实这也是很多同学比较关注的一个问题&#xff0c;下面我们就一起来了解一下IC行业薪资有多高。 不同高校层次硕士-IC设计薪资情况 从不同岗位类型的offer占比情况来看&#xff0c;从事I…

SaaS云HIS系统源码功能介绍

SaaS云HIS首页功能&#xff1a;包括工作计划、预警、主功能菜单、医院机构公告。 一、工作计划 1.值班概况&#xff1a;值班日期、值班时间、值班科室&#xff08;内科、外科等&#xff09; 2.待处理患者&#xff1a;内科人数、外科人数等 病历统计&#xff1a;入院病历、出…

Java冒泡排序(Bubble Sort)算法实例

何为冒泡排序&#xff1f; 冒泡&#xff1a;就像气泡从水中冒出来一样 在冒泡排序中&#xff0c;最小数或最大数取决于您是按升序还是降序对数组进行排序&#xff0c;向上冒泡到数组的开头或结尾。算法描述&#xff1a; 比较相邻的元素。如果第一个比第二个大&#xff0c;就交…

【网络编程】

1.网络基础&#xff08;见PDF文件&#xff09; file:///D:/0graduate/000%E5%AE%9E%E4%B9%A0%E5%B0%B1%E4%B8%9A/C/webserver/4.1/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80.pdf 2.协议 UDP协议 TCP协议 源端口号&#xff1a;发送方端口号目的端口号&#xff1a;接收方端口号序…

Dubbo (1)

目录 认识RPC Dubbo 认识RPC RPC是解决不同JVM之间数据调用的一个思想&#xff0c;比如说现在有2台不同的机器&#xff0c;业务代码需要在这2台机器间调用后台业务代码&#xff0c;RPC就可以解决这2台机器业务代码调用的问题&#xff1a; 而RPC实现流程是什么样的呢&#xff…

中文版gpt-最新的人工智能gpt

最新的人工智能gpt 什么是GPT&#xff1f; GPT是一种自然语言处理和语言生成技术&#xff0c;它能够学习和理解自然语言&#xff0c;并生成高质量的文本。GPT是由OpenAI开发的&#xff0c;它采用了最新的深度学习技术&#xff0c;具备了强大的自我学习能力和语言理解能力。它…

Mybatis关联查询【附实战案例】

目录 相关导读 一、Mybatis一对一关联查询 1. 新增持久层接口方法 2. 新增映射文件对应的标签 3. 新增测试方法 4. 运行效果 二、Mybatis一对多关联查询 1. 新增持久层接口方法 2. 新增映射文件对应的标签 3. 新增测试方法 4. 运行效果 三、Mybatis多对多关联查询 …

HCL Nomad Web 1.0.7发布和新功能验证

大家好&#xff0c;才是真的好。 要问在HCL Notes/Domino系列产品中&#xff0c;谁更新得最快&#xff0c;那么答案一定是HCL Nomad Web。 你看上图右边&#xff0c;从1.0.1更新到1.0.7&#xff0c;都没花多少时间。 从HCL Nomad Web 1.0.5版本开始&#xff0c;可以支持直接…

逐浪智能时代,网易数帆“重写”低代码

如今&#xff0c;越来越多行业正驶入数字化转型的深水区&#xff0c;如何彻底释放数据生产力&#xff0c;成为所有企业的一道必答题。 4月25日&#xff0c;“网易数帆低代码业务战略发布会”在线上举行。在发布会上&#xff0c;网易数帆发布了CodeWave智能开发平台&#xff0c…

C#之Class的实例化过程

总目录 文章目录 总目录前言一、class的成员二、实例化顺序&#xff08;无继承情况&#xff09;1.声明时进行初始化2.在构造函数中初始化 三、实例化顺序&#xff08;有继承情况&#xff09;结语 前言 在平常开发的过程中&#xff0c;经常需要new 一个class&#xff0c;但是呢…

平安银行广州分行:以金融赋能慈善 释放更大社会效能

4月8日&#xff0c;平安银行广州分行“为爱徒步 欢乐‘益’起行”活动在广州市白云区钟落潭镇云溪湾新乡村示范带圆满举行。本次活动由平安银行广州分行主办&#xff0c;通过白云区供销合作联社组织&#xff0c;在助农过程中&#xff0c;同时公益捐步&#xff0c;助力建设云溪湾…

gitlab部署及整合Jenkins持续构建(三)sonarqube9.9安装和使用(一步一坑)

文章目录 postgresql13.0安装1、配置postgresql数据库2、进入postgresql创建数据库 代码质量管理平台--sonarqube安装1、前置依赖下载2、安装unzip并解压sonarqube并移动到/usr/local&#xff1a;3、修改sonarqube相应的配置4、新增用户&#xff0c;并将目录所属权赋予该用户&a…

资料链接 网络/系统/华为

网络&#xff1a; 缺省路由 https://www.cnblogs.com/ricksteves/p/9702546.html AC热备 快搜预览中心https://search.ruijie.com.cn:8447/rqs/preview.html?wdeHAiOjE1NDU4NzUxNDcsIm5iZiI6MTU0NTYxNTk0N302018092015272000303LqqZuvMhE7V7Ygl6r5RWsTHbWazT BGP https:…

nextjs 错误日志收集

最近用nextjs开发一款房产渠道管理的系统&#xff0c;从开始的项目管理&#xff0c;到价格单管理、订单管理、团队管理、中介管理、个人信息管理...等等功能越来越多的时候&#xff0c;前端偶现的问题不容易发现&#xff0c;造成了不必要的麻烦&#xff0c;就想搞个错误日志收集…

地理信息系统有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是几本地理信息系统领域的SCI期刊推荐&#xff1a; International Journal of Geographical Information Science: 这是一个国际性的期刊&#xff0c;它涵盖了地理信息科学的所有领域&#xff0c;包括地图学、遥感、空间分析、地理信息系统、地理信息技术、地球信息学等等…

被chatGPT割了一块钱韭菜

大家好&#xff0c;才是真的好。 chatGPT热度一直上升&#xff0c;让我萌生了一个胆大而创新的想法&#xff0c; 把chatGPT嵌入到Notes客户机中来玩。 考虑到我已经下载了一个chatGPT的Notes应用&#xff08;请见《ChatGPT APIs for HCL DOMINO》&#xff09;&#xff0c;想着…

Shell编程之条件语句

目录 一、条件测试 1&#xff09;test命令 ​编辑 2&#xff09;文件测试 常用的测试操作符 ​编辑 4&#xff09;整数值比较 常用的测试操作符 6&#xff09;逻辑测试 常用的测试操作符 7&#xff09;三元运算符 二、if语句 1&#xff09;单分支结构 2&#xff09…