剖析十大经典二叉树题目:C 语言代码实现与深度解读

news2024/10/8 17:41:46

💯前言

二叉树是数据结构中的重要概念,在算法和编程中有着广泛的应用。以下是十大经典的二叉树题目及其解析与 C 语言代码实现,同时也会说明题目来源。

二叉树的基本概念👉【剖析二叉树】 


目录

💯二叉树的遍历

⭐前序遍历

⭐中序遍历

⭐ 后序遍历

💯二叉搜索树相关

⭐验证二叉搜索树

⭐二叉搜索树的插入

⭐二叉搜索树的删除

💯二叉树的高度与平衡

⭐计算二叉树的高度

⭐平衡二叉树

💯二叉树的路径问题

⭐二叉树的所有路径

⭐路径总和

💯总结 


💯二叉树的遍历

⭐前序遍历

题目链接👉【力扣】

  • 题目描述:按照根节点 - 左子树 - 右子树的顺序遍历二叉树,并输出节点值。
  • C 语言代码实现:
#include <stdio.h>
#include <stdlib.h>

// 定义二叉树节点结构
typedef struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新节点
TreeNode* createNode(int val) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    newNode->val = val;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}
// 前序遍历递归函数
void preorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    printf("%d ", root->val);
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}
  • 代码解析
    • createNode函数用于动态分配内存并创建一个新的二叉树节点,初始化节点的值以及左右子树指针为NULL
    • preorderTraversal是前序遍历的递归实现。首先检查根节点是否为NULL,如果是则直接返回。然后输出根节点的值,接着递归地对左子树进行前序遍历,再对右子树进行前序遍历。这样就按照根节点 - 左子树 - 右子树的顺序访问了二叉树的所有节点。

💝前序遍历递归图解: 

 

 

⭐中序遍历

题目链接👉【力扣】

  • 题目描述:以左子树 - 根节点 - 右子树的顺序遍历二叉树并输出节点值。
  • C 语言代码实现
// 中序遍历递归函数
void inorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    inorderTraversal(root->left);
    printf("%d ", root->val);
    inorderTraversal(root->right);
}
  • 代码解析
    • 中序遍历的递归实现。首先递归地对左子树进行中序遍历,然后输出根节点的值,最后递归地对右子树进行中序遍历。这样就保证了按照左子树 - 根节点 - 右子树的顺序访问节点。对于二叉搜索树,中序遍历会得到一个有序的节点值序列。

 

⭐ 后序遍历

题目链接👉【力扣】

  • 题目描述:按照左子树 - 右子树 - 根节点的顺序遍历二叉树并输出节点值。
  • C 语言代码实现
// 后序遍历递归函数
void postorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    postorderTraversal(root->left);
    postorderTraversal(root->right);
    printf("%d ", root->val);
}
  • 代码解析
    • 后序遍历的递归实现。先递归地对左子树进行后序遍历,再对右子树进行后序遍历,最后输出根节点的值。这种遍历顺序常用于计算二叉树的高度、释放二叉树占用的内存等场景。

 

💯二叉搜索树相关

⭐验证二叉搜索树

题目链接👉【力扣】

  • 题目描述:判断给定的二叉树是否是二叉搜索树。

有效 二叉搜索树定义如下: 

  1. 节点的左子树只包含 小于 当前节点的数。
  2. 节点的右子树只包含 大于 当前节点的数。
  3. 所有左子树和右子树自身必须也是二叉搜索树
  • C 语言代码实现
// 验证二叉搜索树的辅助函数
int isValidBSTHelper(TreeNode* root, TreeNode** prev) {
    if (root == NULL) {
        return 1;
    }
    if (!isValidBSTHelper(root->left, prev)) {
        return 0;
    }
    if (*prev!= NULL && root->val <= (*prev)->val) {
        return 0;
    }
    *prev = root;
    return isValidBSTHelper(root->right, prev);
}

// 验证二叉搜索树的函数接口
int isValidBST(TreeNode* root) {
    TreeNode* prev = NULL;
    return isValidBSTHelper(root, &prev);
}
  • 代码解析
    • isValidBSTHelper是验证二叉搜索树的核心递归函数。它首先递归地检查左子树是否是二叉搜索树,如果不是则直接返回0。然后检查当前节点的值是否大于前一个节点的值(对于中序遍历顺序),如果不满足则返回0。接着更新前一个节点为当前节点,并递归地检查右子树是否是二叉搜索树。
    • isValidBST函数是对外提供的接口函数,它初始化一个prev指针为NULL,然后调用isValidBSTHelper函数开始验证。

 

⭐二叉搜索树的插入

题目链接👉【力扣】

  • 题目描述:在二叉搜索树中插入一个新的节点。
  • C 语言代码实现
// 向二叉搜索树中插入节点
TreeNode* insertIntoBST(TreeNode* root, int val) {
    if (root == NULL) {
        return createNode(val);
    }
    if (val < root->val) {
        root->left = insertIntoBST(root->left, val);
    } else {
        root->right = insertIntoBST(root->right, val);
    }
    return root;
}
  • 代码解析
    • 从根节点开始,如果要插入的值小于当前节点的值,则递归地在左子树中插入;如果大于当前节点的值,则递归地在右子树中插入。如果当前节点为NULL,则创建一个新节点并插入。最后返回更新后的根节点。

 

⭐二叉搜索树的删除

题目链接👉【力扣】

  • 题目描述:从二叉搜索树中删除一个指定节点,并保持二叉搜索树的性质。
  • C 语言代码实现
// 找到二叉搜索树中的最小节点
TreeNode* findMin(TreeNode* node) {
    while (node->left!= NULL) {
        node = node->left;
    }
    return node;
}

// 删除二叉搜索树中的节点
TreeNode* deleteNode(TreeNode* root, int key) {
    if (root == NULL) {
        return root;
    }
    if (key < root->val) {
        root->left = deleteNode(root->left, key);
    } else if (key > root->val) {
        root->right = deleteNode(root->right, key);
    } else {
        if (root->left == NULL) {
            TreeNode* temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            TreeNode* temp = root->left;
            free(root);
            return temp;
        }
        TreeNode* minNode = findMin(root->right);
        root->val = minNode->val;
        root->right = deleteNode(root->right, minNode->val);
    }
    return root;
}
  • 代码解析
    • findMin函数用于在二叉搜索树中找到最小节点,即一直沿着左子树找到最左边的节点。
    • deleteNode函数是删除节点的主要函数。首先找到要删除的节点,如果节点不存在则直接返回当前树。如果要删除的节点是叶子节点,直接删除并返回其非空子树(如果有)。如果节点只有一个子节点,将子节点替换该节点并释放原节点内存。如果节点有两个子节点,找到该节点右子树中的最小节点,将其值赋给要删除的节点,然后删除右子树中的最小节点。

 

💯二叉树的高度与平衡

⭐计算二叉树的高度

题目链接👉【力扣】

  • 题目描述:求二叉树的高度,即从根节点到最远叶子节点的最长路径上的节点数。
  • C 语言代码实现
// 计算二叉树的高度
int treeHeight(TreeNode* root) {
    if (root == NULL) {
        return 0;
    }
    int leftHeight = treeHeight(root->left);
    int rightHeight = treeHeight(root->right);
    return (leftHeight > rightHeight? leftHeight : rightHeight) + 1;
}
  • 代码解析
    • 采用递归的方式计算二叉树的高度。首先判断根节点是否为NULL,如果是则高度为0。然后分别递归地计算左子树和右子树的高度,取两者中的较大值加1作为整棵树的高度。加1是因为要加上根节点本身。

 

⭐平衡二叉树

题目链接👉【力扣】

  • 题目描述:判断一棵二叉树是否是平衡二叉树(左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树)
  • C 语言代码实现
// 判断二叉树是否平衡的辅助函数
int isBalancedHelper(TreeNode* root, int* height) {
    if (root == NULL) {
        *height = 0;
        return 1;
    }
    int leftHeight, rightHeight;
    if (!isBalancedHelper(root->left, &leftHeight)) {
        return 0;
    }
    if (!isBalancedHelper(root->right, &rightHeight)) {
        return 0;
    }
    *height = (leftHeight > rightHeight? leftHeight : rightHeight) + 1;
    if (abs(leftHeight - rightHeight) > 1) {
        return 0;
    }
    return 1;
}

// 判断二叉树是否平衡的函数接口
int isBalanced(TreeNode* root) {
    int height;
    return isBalancedHelper(root, &height);
}
  • 代码解析
    • isBalancedHelper函数是判断平衡二叉树的核心递归函数。首先处理空树的情况,将高度设置为0并返回1表示空树是平衡的。然后递归地计算左子树和右子树的高度,并检查它们的高度差是否超过1,同时递归地检查左子树和右子树是否本身是平衡的。
    • isBalanced函数是对外接口,它初始化一个高度变量,然后调用isBalancedHelper函数进行判断并返回结果。

 

💯二叉树的路径问题

⭐二叉树的所有路径

题目链接👉【力扣】

  • 题目描述:输出二叉树从根节点到所有叶子节点的路径。
  • C 语言代码实现
#include <string.h>

// 二叉树的所有路径辅助函数
void binaryTreePathsHelper(TreeNode* root, char** paths, int* pathCount, char* currentPath, int pathLen) {
    if (root == NULL) {
        return;
    }
    currentPath[pathLen] = root->val + '0';
    currentPath[pathLen + 1] = '\0';
    if (root->left == NULL && root->right == NULL) {
        paths[*pathCount] = (char*)malloc((pathLen + 2) * sizeof(char));
        strcpy(paths[*pathCount], currentPath);
        (*pathCount)++;
    }
    binaryTreePathsHelper(root->left, paths, pathCount, currentPath, pathLen + 1);
    binaryTreePathsHelper(root->right, paths, pathCount, currentPath, pathLen + 1);
}

// 二叉树的所有路径函数接口
char** binaryTreePaths(TreeNode* root, int* returnSize) {
    char** paths = (char**)malloc(100 * sizeof(char*));  // 假设最多有100条路径,可根据实际情况调整
    int pathCount = 0;
    char currentPath[1000];  // 假设路径长度最大为1000,可根据实际情况调整
    binaryTreePathsHelper(root, paths, &pathCount, currentPath, 0);
    *returnSize = pathCount;
    return paths;
}
  • 代码解析
    • binaryTreePathsHelper函数是实现输出所有路径的递归辅助函数。首先处理空节点情况,直接返回。然后将当前节点的值添加到路径字符串中,并检查当前节点是否为叶子节点,如果是则将当前路径复制到结果数组中并更新路径计数。接着递归地对左子树和右子树进行处理,每次将路径长度加1
    • binaryTreePaths函数是对外接口,它分配内存用于存储路径结果,初始化相关变量,然后调用binaryTreePathsHelper函数进行计算,并返回路径数组和路径数量。

 

 

⭐路径总和

题目链接👉【力扣】

  • 题目描述:给定一棵二叉树和一个整数,判断是否存在从根节点到叶子节点的路径,使得路径上所有节点值之和等于给定的整数。
  • C 语言代码实现
// 路径总和辅助函数
int hasPathSumHelper(TreeNode* root, int targetSum, int currentSum) {
    if (root == NULL) {
        return 0;
    }
    currentSum += root->val;
    if (root->left == NULL && root->right == NULL && currentSum == targetSum) {
        return 1;
    }
    return hasPathSumHelper(root->left, targetSum, currentSum) || hasPathSumHelper(root->right, targetSum, currentSum);
}

// 路径总和函数接口
int hasPathSum(TreeNode* root, int targetSum) {
    return hasPathSumHelper(root, targetSum, 0);
}
  • 代码解析
    • hasPathSumHelper函数是判断路径总和的递归辅助函数。首先处理空节点情况,返回0表示当前路径不符合条件。然后将当前节点的值加到当前路径和中,检查当前节点是否为叶子节点且路径和是否等于目标和,如果是则返回1表示找到符合条件的路径。最后递归地对左子树和右子树进行检查,只要左子树或右子树中有符合条件的路径,就返回1
    • hasPathSum函数是对外接口,它初始化当前路径和为0,然后调用hasPathSumHelper函数开始判断。

 

💯总结 

 

 通过对这十大经典二叉树题目的详细解析和 C 语言代码实现,希望读者能够更深入地理解二叉树的相关知识和算法,提升在数据结构和算法方面的编程能力和问题解决能力

无论是在学习过程中还是应对实际的编程挑战,这些知识都将具有重要的价值。 

 💝💝💝感谢你看到最后,点个赞再走吧!💝💝💝

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

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

相关文章

AI大模型真的是大龄程序员的新的出路吗?_大龄程序员ai创业

前言 在IT行业的高速运转中&#xff0c;许多资深程序员到了一定年龄后&#xff0c;会发现自己陷入了职业发展的瓶颈。尤其是在北京这样的大厂&#xff0c;业务波动、部门调整以及裁员风险&#xff0c;都让“40”的程序员们感受到了前所未有的压力。当昔日的技术热情逐渐消退&a…

在C#中使用适配器Adapter模式和扩展方法解决面向对象设计问题

之前有阵子在业余时间拓展自己的一个游戏框架&#xff0c;结果在实现的过程中发现一个设计问题。这个游戏框架基于MonoGame实现&#xff0c;在MonoGame中&#xff0c;所有的材质渲染&#xff08;Texture Rendering&#xff09;都是通过SpriteBatch类来完成的。举个例子&#xf…

新书速览|你好,C++

《你好&#xff0c;C》 本书内容 《你好&#xff0c;C》主要介绍C开发环境的搭建、基础语法知识、面向对象编程思想以及标准模板库的应用&#xff0c;特别针对初学者在学习C过程中可能遇到的难点提供了解决方案。全书共分13章&#xff0c;以一个工资程序的不断优化和完善为线索…

ChatGPT助力文献综述写作:提升效率与写作技巧!

文献综述在论文写作中占有举足轻重的地位。它不仅帮助我们梳理已有的研究成果&#xff0c;还能为自己的研究奠定基础。许多同学在撰写文献综述时常常感到头疼&#xff1a;如何处理海量的信息&#xff1f;如何将不同的观点有条理地整合起来&#xff1f;再加上学术语言的高要求&a…

定时任务。

引入 1.启动类上加上注解 2.新建一个定时任务的管理类&#xff0c;交给Spring管理 案例 案例1&#xff1a;fixedRate //上次任务开始到下次任务开始的时间间隔为5秒 //每隔5秒执行一次,不需要等上个任务执行完 Scheduled(fixedRate 5000) public void mask01() throws Inte…

python:web自动化工具selenium安装和配置(1)

UI自动化测试 UI自动化测试&#xff08;User Interface Automation Testing&#xff09;是一种通过编写脚本或使用自动化测试工具&#xff0c;对界面&#xff08;UI&#xff09;进行自动化测试的方法。原理主要是模拟用户打开客户端或网页的UI界面&#xff0c;自动化执行用户界…

【Java 问题】基础——泛型

接上文 泛型 47.Java 泛型了解么&#xff1f;什么是类型擦除&#xff1f;介绍一下常用的通配符&#xff1f; 47.Java 泛型了解么&#xff1f;什么是类型擦除&#xff1f;介绍一下常用的通配符&#xff1f; 什么是泛型&#xff1f; Java 泛型&#xff08;generics&#xff09;是…

REINFORCEMENT LEARNING THROUGH ACTIVE INFERENCE

摘要 强化学习&#xff08;RL&#xff09;的核心原则是智能体寻求最大化累积奖励之和。相比之下&#xff0c;主动推理&#xff0c;认知和计算神经科学中的一个新兴框架&#xff0c;提出代理人采取行动&#xff0c;以最大限度地提高有偏见的生成模型的证据。在这里&#xff0c;…

上门安装维修系统小程序开发详解及源码示例

随着智能家居和设备的普及&#xff0c;消费者对上门安装和维修服务的需求日益增加。为了满足这一市场需求&#xff0c;开发一款上门安装维修系统小程序成为了一种有效的解决方案。本文将详细介绍上门安装维修系统小程序的开发过程&#xff0c;并提供一个简单的源码示例&#xf…

人工智能的未来

引言 人工智能的未来发展将是科技与人类社会深度融合的过程。随着技术的不断进步&#xff0c;AI将在全球经济、文化、政治及道德伦理等领域产生深远影响。本文将探讨人工智能在未来可能的技术进步、应用领域、社会影响、伦理挑战&#xff0c;以及对全球未来的展望。 一、技术前…

数据结构之——二叉树

一、二叉树的基本概念 二叉树是数据结构中的重要概念&#xff0c;每个节点最多有两个子树&#xff0c;分别为左子树和右子树。这种结构具有明确的层次性和特定的性质。 二叉树有五种基本形态&#xff1a; 空二叉树&#xff1a;没有任何节点。只有一个根结点的二叉树&#xff…

【HTTPS】深入解析 https

我的主页&#xff1a;2的n次方_ 1. 背景介绍 在使用 http 协议的时候是不安全的&#xff0c;可能会出现运营商劫持等安全问题&#xff0c;运营商通过劫持 http 流量&#xff0c;篡改返回的网页内容&#xff0c;例如广告业务&#xff0c;可能会通过 Referer 字段 来统计是…

kubernetes get pods的STATUS字段显示ImagePullBackOff 的解决办法

问题&#xff1a; [rootmaster ingress]# kubectl -n ingress-nginx get pods NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-mcrc6 0/1 ImagePullBackOff 0 37m ingress-…

掌握RocketMQ——基本概念和系统架构

简述RcoketMQ 概念&#xff1a;RocketMQ是一个开源的分布式消息中间件&#xff0c;由阿里巴巴开发并贡献给Apache软件基金会。它用于处理高吞吐量、低延迟的消息传递&#xff0c;并广泛应用于现代分布式系统中。 1 基本概念 1.1 消息 (Message) 概念&#xff1a;消息是信息传…

自定义协议以及序列化和反序列化

我们知道TCP是全双工的&#xff0c;可以同时进行发收&#xff0c;因为他有一个发送缓冲区和一个接收缓冲区 我们使用write其实是把数据拷贝到发送缓冲区&#xff0c;使用read接收缓冲区的数据&#xff0c;其实是把数据拷贝到文件缓冲区里&#xff0c;发送的过程中&#xff0c;我…

脸书(Facebook)高效开发国外客户的6个技巧

Facebook作为全球使用人数最多的社媒平台&#xff0c;全球三分之一的人都在用。做外贸的话基本上是必须要去掌握的一个平台&#xff0c;因为通过Facebook是可以开发到很多其他渠道平时开发不到的优质客户的。 Facebook跟LinkedIn不同&#xff0c;LinkedIn比较偏向于大B的客户&…

传热学一些“数”和意义

物体单位面积上的导热热阻/单位表面积上的对流换热热阻 无量纲时间 Nu与Bi的表达式相同&#xff0c;但是意义是无量纲的h。它们表达式里的长度取值不同&#xff0c;比如同样一个平板&#xff0c;Bi的L是厚度&#xff0c;Nu是长度&#xff0c;因为Bi面向固体&#xff0c;λ为固…

八种基本服务器类型,看这篇完全够了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 上午好&#xff0c;我的网工朋友。 服务器作为网络基础设施的核心组件&#xff0c;其重要性不言而喻。 无论是个人空间还是大型企业的数据中心&…

激波是什么?

你肯定能听懂。激波&#xff0c;激烈的波&#xff0c;代表特征&#xff1a;激波扫过你时&#xff0c;重则五脏震动&#xff0c;支离破碎。轻则耳膜震动&#xff0c;隆隆作响&#xff0c;当然也有相对你而言尺度很小的激波&#xff0c;没啥伤害。 所以激波&#xff0c;和相对于…

【VScode】VScode如何离线安装扩展

VScode如何离线安装扩展 一&#xff0c;简介二&#xff0c;操作步骤2.1 扩展下载2.2 扩展安装 三&#xff0c;总结 一&#xff0c;简介 本文以“C/C Extension Pack”扩展为例&#xff0c;介绍如何在没有网络的环境下给VScode安装扩展&#xff0c;供参考。 二&#xff0c;操作…