二叉树的前序遍历 、二叉树的最大深度、平衡二叉树、二叉树遍历【LeetCode刷题日志】

news2024/12/24 20:33:58

目录

一、二叉树的前序遍历 

方法一:全局变量记录节点个数

方法二:传址调用记录节点个数

二、二叉树的最大深度

三、平衡二叉树

四、二叉树遍历


一、二叉树的前序遍历 

 

方法一:全局变量记录节点个数

计算树的节点数:
函数TreeSize用于递归地计算二叉树中的节点数。如果树为空(即根节点为NULL),则返回0。否则,返回左子树的节点数、右子树的节点数和1(表示当前节点)的总和。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;          // 节点的值  
 *  struct TreeNode *left;  // 指向左子节点的指针  
 *  struct TreeNode *right; // 指向右子节点的指针
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
//先求树有几个节点
int TreeSize(struct TreeNode* root)
{
    // 如果树为空(即根节点为NULL),则返回0  
    // 否则,返回左子树节点数 + 右子树节点数 + 1(当前节点)
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

_prevOrder函数:
这是一个辅助函数,用于递归地执行前序遍历。它首先将当前节点的值存储在数组a中,然后递归地遍历左子树和右子树。注意,这里直接使用了全局变量i来更新数组索引。

定义一个全局变量i

// 前序遍历二叉树的辅助函数  
void _prevOrder(struct TreeNode* root, int* a) {  
    // 如果当前节点为空,则直接返回  
    if (root == NULL) {  
        return;  
    }  
    // 将当前节点的值存储到数组中,并使用全局变量i作为索引  
    a[i] = root->val;  
    // 递增全局变量i  
    ++i;  
      
    // 递归遍历左子树  
    _prevOrder(root->left, a);  
    // 递归遍历右子树  
    _prevOrder(root->right, a);  
}


preorderTraversal函数:
这是主函数,用于执行前序遍历并返回结果数组。它首先使用TreeSize函数计算树的节点数,然后动态分配一个足够大的整数数组来存储结果。接下来,它调用_prevOrder函数来执行前序遍历,并填充数组。最后,它设置returnSize为树的节点数,并返回结果数组。

// 执行前序遍历并返回结果数组的主函数  
int* preorderTraversal(struct TreeNode* root, int* returnSize) {  
    //每次调用函数时,都要把i初始化
    //如果没有初始化,则i会一直叠加,无法重复使用
    i = 0;  
    // 调用TreeSize函数计算二叉树的节点数  
    int size = TreeSize(root);  
    // 动态分配结果数组,大小为节点数  
    int* a = (int*)malloc(size * sizeof(int));  
    // 调用辅助函数_prevOrder执行前序遍历,填充数组a  
    _prevOrder(root, a);  
    // 设置返回数组的大小为树的节点数,通过指针参数returnSize返回  
    *returnSize = size;        
    // 返回结果数组a的指针  
    return a;                  
}

方法二:传址调用记录节点个数

前面与方法一相同,不再过多赘述

_prevOrder 函数:
辅助函数,用于递归地执行前序遍历。它接受三个参数:当前节点 root、用于存储遍历结果的数组 a 和一个指向整数的指针 pi(表示当前数组索引)。函数首先将当前节点的值存储在数组 a 的相应位置,然后递增索引 pi。接下来,它递归地遍历左子树和右子树。

// 前序遍历二叉树的辅助函数  
void _prevOrder(struct TreeNode* root, int* a, int* pi) {  
    // 如果当前节点为空,则直接返回  
    if (root == NULL) {  
        return;  
    }  
    // 将当前节点的值存储到数组中,并递增索引pi  
    a[*pi] = root->val;  
    ++(*pi);  
      
    // 递归遍历左子树  
    _prevOrder(root->left, a, pi);  
    // 递归遍历右子树  
    _prevOrder(root->right, a, pi);  
}

preorderTraversal 函数:
这是主函数,用于执行前序遍历并返回结果数组。它首先调用 TreeSize 函数(虽然这里没有给出 TreeSize 的实现,但我们可以假设它的功能是计算树的节点数)来计算树的节点数,然后动态分配一个足够大的整数数组来存储结果。接着,它调用 _prevOrder 函数来执行前序遍历,并填充数组。最后,它设置 returnSize 为树的节点数,并返回结果数组。

int* preorderTraversal(struct TreeNode* root, int* returnSize) {  
    int i = 0; // 初始化索引为0  
    int size = TreeSize(root); // 假设TreeSize函数能正确计算节点数  
    int* a = (int*)malloc(size * sizeof(int)); // 动态分配数组  
    _prevOrder(root, a, &i); // 执行前序遍历,填充数组  
  
    *returnSize = size; // 设置返回数组的大小  
  
    return a; // 返回结果数组  
}

二、二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
int maxDepth(struct TreeNode* root) {  
    // 如果根节点为空,说明树是空的,因此深度为0。  
    if (root == NULL)  
        return 0;  
      
    // 递归地计算左子树的最大深度。  
    int leftDepth = maxDepth(root->left);  
      
    // 递归地计算右子树的最大深度。  
    int rightDepth = maxDepth(root->right);  
  
    // 返回左、右子树中深度较大的一个,并加上当前节点的高度1。  
    return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;  
}

三、平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
 
int maxDepth(struct TreeNode* root) {  
    // 如果根节点为空,说明树是空的,因此深度为0。  
    if (root == NULL)  
        return 0;  
  
    // 递归计算左子树的最大深度。  
    int leftDepth = maxDepth(root->left);  
    // 递归计算右子树的最大深度。  
    int rightDepth = maxDepth(root->right);  
  
    // 返回左、右子树中较大的深度值加1(加上当前节点的高度)。  
    return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;  
}
bool isBalanced(struct TreeNode* root) {  
    // 如果根节点为空,那么这棵空树被认为是平衡的。  
    if (root == NULL)  
        return true;  
  
    // 计算左子树的最大深度。  
    int leftDepth = maxDepth(root->left);  
    // 计算右子树的最大深度。  
    int rightDepth = maxDepth(root->right);  
  
    // 判断当前节点的左右子树深度差是否小于等于1,并且左右子树本身也都是平衡的。   
    return abs(leftDepth - rightDepth) <= 1  
        && isBalanced(root->left)  // 递归检查左子树是否平衡。  
        && isBalanced(root->right); // 递归检查右子树是否平衡。  
}

四、二叉树遍历

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。 

#include <stdio.h>  
#include <stdlib.h> // 需要包含stdlib.h来使用malloc和exit函数  
  
// 定义二叉树节点的结构体  
typedef struct TreeNode  
{  
    struct TreeNode* left;  // 左子树指针  
    struct TreeNode* right; // 右子树指针  
    char val;               // 节点值  
} TNode;  
  
// 创建一个二叉树的函数,a是包含节点值的字符串,pi是指向当前要处理的字符的索引的指针  
TNode* CreatTree(char* a, int* pi)  
{  
    // 如果当前字符是'#',表示这是一个空节点  
    if (a[*pi] == '#')  
    {  
        ++(*pi); // 增加索引  
        return NULL; // 返回空指针表示这是一个空节点  
    }  
  
    // 为新节点分配内存  
    TNode* root = (TNode*)malloc(sizeof(TNode));  
    if (root == NULL)  
    {  
        printf("malloc fail\n"); // 如果分配失败,输出错误信息  
        exit(-1); // 退出程序  
    }  
  
    // 设置节点的值,并增加索引  
    root->val = a[*pi];  
    ++(*pi);  
  
    // 递归地创建左子树和右子树  
    root->left = CreatTree(a, pi);  
    root->right = CreatTree(a, pi);  
      
    return root; // 返回新创建的节点  
}  
  
// 中序遍历二叉树的函数  
void InOrder(TNode* root) // 注意:函数名应该是InOrder,而不是InOeder(这里有一个拼写错误)  
{  
    if (root == NULL) // 如果节点为空,直接返回  
        return;  
    InOrder(root->left);  // 遍历左子树  
    printf("%c ", root->val); // 输出节点的值  
    InOrder(root->right); // 遍历右子树  
}  
  
int main() {  
    char str[100]; // 存储节点值的字符串  
  
    scanf("%s", str); // 读取输入字符串,注意应该直接传入数组名
    int i = 0; // 索引初始化为0  
    TNode* root = CreatTree(str, &i); // 创建二叉树,并将根节点赋值给root  
    InOrder(root); // 中序遍历二叉树并输出结果  
  
    return 0; 
}

祝大家新年快乐!!!

看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注!

你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。

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

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

相关文章

LLM之RAG理论(四)| RAG高级数据索引技术

本文将重新审视分块技术以及其他方法&#xff0c;包括查询增强、层次结构和知识图谱。 一、简单RAG架构快速概览 在2023年年初&#xff0c;我的主要关注点集中在Vector DB及其在更广泛的设计领域中的表现上。然而&#xff0c;随着2023年的收尾&#xff0c;这一领域出现了重大进…

Spring MVC - Controller的创建与使用

控制器Controller是处理器&#xff0c;是真正处理请求的组件 1 创建Controller 一般在src/main/java/com/qdu下建立一个controller包用来存放所有控制器。当创建一个控制器时&#xff0c;首先要记得使用Controller标记将该类注册成为一个控制器类。 然后在SpringMVCConfig类…

项目 杂碎 知识点 汇总!!!

Vue !!! setup生命周期 使用 nextTick &#xff01;&#xff01;获取节点 onMounted中可以使用JS&#xff0c;获取节点&#xff0c;setup生命周期无法获取节点 vue实现文本粘贴复制 Vue遍历对象 1、使用v-for指令&#xff1a;可以直接遍历对象的键和值 2、使用 Object.keys…

git基础概念和常用命令(日常开发收藏备用)

目录 ### 常用命令 ### 远程仓库与克隆 ### 分支管理 ### 子模块&#xff08;Submodule&#xff09; ### 其他高级操作 ### 交互式暂存&#xff08;Interactive Staging&#xff09; ### cherry-pick ### rebase ### reflog与reset ### 子树合并&#xff08;Subtree …

【Maven】<scope>provided</scope>

在Maven中&#xff0c;“provided”是一个常用的依赖范围&#xff0c;它表示某个依赖项在编译和测试阶段是必需的&#xff0c;但在运行时则由外部环境提供&#xff0c;不需要包含在最终的项目包中。下面是对Maven scope “provided”的详细解释&#xff1a; 编译和测试阶段可用…

Vue3全局属性app.config.globalProperties

文章目录 一、概念二、实践2.1、定义2.2、使用 三、最后 一、概念 一个用于注册能够被应用内所有组件实例访问到的全局属性的对象。点击【前往】访问官网 二、实践 2.1、定义 在main.ts文件中设置app.config.globalPropertie import {createApp} from vue import ElementPl…

.NET国产化改造探索(二)、银河麒麟安装人大金仓数据库

随着时代的发展以及近年来信创工作和…废话就不多说了&#xff0c;这个系列就是为.NET遇到国产化需求的一个闭坑系列。接下来&#xff0c;看操作。 上一篇介绍了如何安装银河麒麟操作系统&#xff0c;这篇文章详细介绍下如何在银河麒麟操作系统上安装人大金仓数据库。 准备安…

LangChain.js 实战系列:搭配 LangSmith 实现调试、监控、测试

&#x1f4dd; LangChain.js 是一个快速开发大模型应用的框架&#xff0c;它提供了一系列强大的功能和工具&#xff0c;使得开发者能够更加高效地构建复杂的应用程序。LangChain.js 实战系列文章将介绍在实际项目中使用 LangChain.js 时的一些方法和技巧。 LangSmith 是 LangCh…

RK3568平台开发系列讲解(Linux系统篇)PWM系统编程

🚀返回专栏总目录 文章目录 一、什么是PWM二、PWM相关节点三、PWM应用编程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 PWM 的系统编程。 一、什么是PWM PWM,即脉冲宽度调制(Pulse Width Modulation)

2023年下半年信息系统项目管理师考试

目录 引言 结果 论文 案例分析 综合知识 总结 引言 2023年下半年参加了信息系统项目管理师考试&#xff0c;考试结果情理之中&#xff0c;意料之外。论文压线&#xff0c;综合和案例差一分。从个人参加考试的整个过程来看&#xff0c;属于历史性的突破。以本文&#xff…

稳定币记录

稳定币&#xff1a; 稳定币&#xff08;Stablecoin&#xff09;是一种加密货币&#xff0c;其设计目的是维持相对稳定的价值&#xff0c;通常与某种法定货币&#xff08;如美元、欧元&#xff09;或其他资产&#xff08;如黄金&#xff09;挂钩。稳定币通过将加密货币与相应的…

详解Vue3中的鼠标事件mousemove、mouseover和mouseout

本文主要介绍Vue3中的常见鼠标事件mousemove、mouseover和mouseout。 目录 一、mousemove——鼠标移动事件二、mouseover——鼠标移入事件三、mouseout——鼠标移出事件 下面是Vue 3中常用的鼠标事件mousemove、mouseover和mouseout的详解。 一、mousemove——鼠标移动事件 鼠…

DevC++ easyx实现视口编辑--像素绘图板与贴图系统

到了最终成果阶段了&#xff0c;虽然中间有一些代码讲起来没有意思&#xff0c;纯靠debug,1-1解决贴图网格不重合问题&#xff0c;这次是一个分支结束。 想着就是把瓦片贴进大地图里。 延续这几篇帖子&#xff0c;开发时间也从2023年的4月16到了6月2号&#xff0c;80小时基本…

【K8S 部署】基于kubeadm搭建Kurbernetes集群

目录 一、基本架构 二、环境准备: 三、安装部署 1、所有节点安装docker 2、、所有节点安装kubeadm&#xff0c;kubelet和kubectl 3、配置网络--flannel 4、测试 pod 资源创建 四、安装部署与k8s集群对接的Harbor仓库 五、Dashboard安装部署&#xff1a; 一、基本架构…

jupyter notebook打开其他盘的文件

jupyter notebook打开其他盘文件 打开jupyter notebook打开terminal输入&#xff1a;jupyter-notebook 路径打开你想打开的工程的文件 打开jupyter notebook 打开terminal 输入&#xff1a;jupyter-notebook 路径 打开你想打开的工程的文件

【中小型企业网络实战案例 六】配置链路聚合

相关文章学习&#xff1a; 【中小型企业网络实战案例 五】配置可靠性和负载分担 热门IT课程【视频教程】&#xff08;思科、华为、红帽、oracle等技术&#xff09;https://xmws-it.blog.csdn.net/article/details/134398330?spm1001.2014.3001.5502 当CORE1或者CORE2的上…

【Elasticsearch源码】 分片恢复分析

带着疑问学源码&#xff0c;第七篇&#xff1a;Elasticsearch 分片恢复分析 代码分析基于&#xff1a;https://github.com/jiankunking/elasticsearch Elasticsearch 8.0.0-SNAPSHOT 目的 在看源码之前先梳理一下&#xff0c;自己对于分片恢复的疑问点&#xff1a; 网上对于E…

微服务雪崩问题及解决方案

雪崩问题 微服务中&#xff0c;服务间调用关系错综复杂&#xff0c;一个微服务往往依赖于多个其它微服务。 微服务之间相互调用&#xff0c;因为调用链中的一个服务故障&#xff0c;引起整个链路都无法访问的情况。 如果服务提供者A发生了故障&#xff0c;当前的应用的部分业务…

机器学习(二) -- 数据预处理(2)

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理&#xff08;1-3&#xff09; 机器学习&#xff08;三&#xff09; -- 特征工程&#xff08;1-2&#xff09; 未完待续…… 目录 系列文章目录 前言 四、【数…

7、InternVL

简介 github demo 使用网络获取的油画图片&#xff0c;InternVL识别还算可以。 使用stable diffusion生成的图片&#xff0c;InternVL能很好的识别。 权重 huggingface地址 模型搭建 github地址 下载源码 git clone https://github.com/OpenGVLab/InternVL.git创建环…