【数据结构】二叉树的节点数,叶子数,第K层节点数,高度,查找x节点,判断是否为完全二叉树等方法

2023-09-20 22:01:49

在这里插入图片描述

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍

一、二叉数的结构体

每一个节点有
1.数据域_data
2.指向左子树的指针:_left
3.指向右子树的执指针:_right

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

二、构建二叉树,供后续测试使用

在这里插入图片描述

三、二叉树销毁

// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreeDestory(root->_left);
	BinaryTreeDestory(root->_right);
	free(root);
}

四、构建节点

//构建节点

BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	node->_data = x;
	node->_left = NULL;
	node->_right = NULL;

	return node;
}

五、二叉树的高度:

fmax函数的头文件:<math.h>
思路:每次选择左右子树中大的那一棵树,对其+1;

1.代码:

//树的高度

int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	return fmax(TreeHeight(root->_left), TreeHeight(root->_right)) + 1;
}

2.测试结果:

在这里插入图片描述

二叉树节点个数

思路:如果当前节点为NULL;则返回0;如果不是NULL;则向左右子树递归并+1;

1.代码:

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 : BinaryTreeSize(root->_left) 
	+ BinaryTreeSize(root->_right) + 1;
}


2.测试结果:

在这里插入图片描述

六、二叉树叶子节点个数

思路:
1.向下递归的条件是当前节点左或者右节点有一个为空,一个不为空。
2.当不满足下面的if语句时,就会return 左右两个节点,从而递归继续向下寻找叶子节点,
3.直到当前节点为空时,就停止返回0;或者找到叶子节点,返回1

1.代码:

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	
	//向下递归的条件是当前节点左或者右节点有一个为空,一个不为空。
	//当不满足下面的if语句时,就会return 左右两个节点,从而递归继续向下寻找叶子节点,
	//直到当前节点为空时,就停止返回0;或者找到叶子节点,返回1
	if (root == NULL)
		return 0;
	if (root->_left == NULL && root->_right == NULL)
		return 1;
	return BinaryTreeLeafSize(root->_left) 
	+ BinaryTreeLeafSize(root->_right);
}

2.测试结果:

在这里插入图片描述

七、二叉树第k层节点个数

思路:
1.当找到第k==1,就返回1,意思是第k层个数+1;
2.当节点为空时,就结束向下递归,开始往回走。
3.如果不满足if条件,就继续向下递归。

1.代码:

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	//当找到第k==1,就返回1,意思是第k层个数+1;
	//当节点为空时,就结束向下递归,开始往回走。
	//如果不满足if条件,就继续向下递归。
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return  BinaryTreeLevelKSize(root->_left, k - 1) 
	+ BinaryTreeLevelKSize(root->_right, k - 1);
}

2.测试结果:

在这里插入图片描述

八、二叉树查找值为x的节点

思路;
1.当root==NULL时,说明当前子树中没有没有找到,返回NULL
2.当root->_data==x时,就return 当前节点,停止向下递归,开始向上回。
3.如果不满足上面两个if条件,就向下递归左,再右节点,
4.如果root->_data == x成立,返回的就不是空值通过if判断,并返回tmp。
5.在一次递归中,如果没有找到等于x的节点,和root=NULL两个条件时,就返回NULL;

1.代码:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	
	//当root==NULL时,说明当前子树中没有没有找到,返回NULL
	//当root->_data==x时,就return 当前节点,停止向下递归,开始向上回。
	//如果不满足上面两个if条件,就向下递归左,再右节点,
	//如果root->_data == x成立,返回的就不是空值通过if判断,并返回tmp。
	//在一次递归中,如果没有找到等于x的节点,和root=NULL两个条件时,就返回NULL;
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	BTNode* tmp = NULL;
	
	tmp=BinaryTreeFind(root->_left, x);
	if (tmp)
		return tmp;
	tmp = BinaryTreeFind(root->_right, x);
	if (tmp)
		return tmp;
	return NULL;
}


2.测试结果:

查询二叉树中节点值=3的节点。
在这里插入图片描述查询

九、判断二叉树是否是完全二叉树

思路:
1.开始层序遍历,直到遇到NULL为止。
2.从遇到NULL的位置开始继续向下遍历,如果还能遇到非空节点,则说明不是完全二叉树。

1.代码:

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	Que q;
	QueueInit(&q);
	//开始层序遍历,直到遇到NULL为止
	if (root)
		QueuePush(&q,root);
	while (!QueueEmpty(&q))
	{
		BTNode* tmp = QueueFront(&q);
		if (tmp == NULL)
			return false;
		QueuePush(&q,tmp->_left);
		QueuePush(&q,tmp->_right);
		QueuePop(&q);
	}
	//从遇到NULL的位置开始继续向下遍历,如果还能遇到非空节点,则说明不是完全二叉树。
	while (!QueueEmpty(&q))
	{
		BTNode* tmp = QueueFront(&q);
		QueuePop(&q);
		if (tmp != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}


2.测试结果:

在这里插入图片描述

十、补充:队列代码

Queue.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once

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

typedef struct BinaryTreeNode* QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Que;

void QueueInit(Que* pq);
void QueueDestroy(Que* pq);
void QueuePush(Que* pq, QDataType x);
void QueuePop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
bool QueueEmpty(Que* pq);
int QueueSize(Que* pq);

Queue.c

#include "Queue.h"

void QueueInit(Que* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueueDestroy(Que* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueuePush(Que* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}

	pq->size++;
}

void QueuePop(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}

	pq->size--;
}

QDataType QueueFront(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

QDataType QueueBack(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

bool QueueEmpty(Que* pq)
{
	assert(pq);

	return pq->head == NULL;
}

int QueueSize(Que* pq)
{
	assert(pq);

	return pq->size;
}
更多推荐

优化测试准备-通过仿真诊断提高效率

现如今,随着车辆中电子器件和软件数量的快速增加,直接在车辆上测试50-150个ECU变得越来越复杂,且需测试的内容也不再局限于单独的系统,而是包括了各个系统之间的交互,最终导致测试过程中的工作量呈指数级增长。一自动化测试减少了测试工作量面对日益增长的工作量,实现自动化测试可能是解决这个问题的一大关键。对此,必须提升效力

linux万字图文学习进程信号

1.信号概念信号是进程之间事件异步通知的一种方式,属于软中断。1.1linux中我们常用Ctrl+c来杀死一个前台进程1.Ctrl-C产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。2.Shell可以同时运行一个前台进程和任意多个后台进程,

mysql数据库备份(mysqldump)

mysqldump命令备份数据mysqldump-uroot-p--databases数据库1数据库2>xxx.sqlmysqldump常用操作示例1.备份全部数据库的数据和结构mysqldump-uroot-p123456-A>/data/mysqlbackup/mydb.sql2.备份全部数据库的结构(加-d参数)

计算机竞赛 深度学习 大数据 股票预测系统 - python lstm

文章目录0前言1课题意义1.1股票预测主流方法2什么是LSTM2.1循环神经网络2.1LSTM诞生2如何用LSTM做股票预测2.1算法构建流程2.2部分代码3实现效果3.1数据3.2预测结果项目运行展示开发环境数据获取最后0前言🔥优质竞赛项目系列,今天要分享的是🚩深度学习大数据股票预测系统该项目较为新颖,适合作为竞

SpringMVC之JSON返回&异常处理机制

一.什么是SpringMVC之JSON返回&异常处理机制二.Json处理导入pom.xml依赖导入Spring-Mvc.xml编写JsonController编写Sql语句测试结果json转换的注解测试结果(@JsonIgnore)三.全局异常处理机制为什么要全局异常处理异常处理思路​编辑自写一个错误代码​编辑输出结果

【vue组件】使用element-ui table 实现嵌套表格 点击展开时获取数据

应用场景是这样主表格的数据是所有的学校然后点击展开的时候,获取学校下相应班级的数据并且班级要能选择后生成图表,但所有的班级最多选择5个首先是嵌套表格<div><el-table:data="tableDisplayData"id="chartTableExpand"style="width:100%"ref="char

基于SpringBoot的点餐系统

基于SpringBoot+Vue的点餐系统、食堂餐厅点餐系统、前后端分离开发语言:Java数据库:MySQL技术:SpringBoot、Vue、MybaitsPlus、ELementUI工具:IDEA/Ecilpse、Navicat、Maven【主要功能】角色:管理员、用户管理员:菜品管理、桌位管理、菜品管理、类别管理

侯捷老师C++课程:C++2.0 新特性

C++2.0新特性第一讲:语言variatictemplates参数包在类模板中,模板参数包必须是最后一个模板形参.而在函数模板中则不必!!!这个之前提过了,就不细谈了下面那三个分别对应:typename...Types//模板参数包constTypes&...args//函数参数类型包print(args...)//

Java中运用BigDecimal对字符串的数值进行加减乘除等操作

系列文章目录SpringBoot+Vue3实现登录验证码功能Java实现发送邮件(定时自动发送邮件)换个角度使用Redis去解决跨域存取Session问题Redis缓存穿透、击穿、雪崩问题及解决方法SpringCache的使用–快速上手篇List<HashMap<String,String>>实现自定义字符串排序(ke

HTML5 游戏开发实战 | 推箱子

经典的推箱子是一个来自日本的古老游戏,目的是在训练玩家的逻辑思考能力。在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙地利用有限的空间和通道,合理安排移动的次序和位置,才能顺利地完成任务。推箱子游戏功能如下:游戏运行载入相应的地图,屏幕中出现一个推箱子的工人,

我想设计一套游戏的奖励系统,有什么值得注意的?

游戏上:游戏成就系统的价值游戏中的成就可以延长游戏时间,让玩家不仅仅是将游戏通关,而是必须完成游戏内所有挑战及发现秘密,这些成就可以与游戏本身的目标一致,也可以独立于游戏的主要或次要目标之外,玩家必须以特别的方式完成游戏才能取得。具体而言:增加游戏收益:与打BOSS掉装备一样,徽章、坐骑、小宠物和称号等成就奖励,需要玩

热文推荐