C语言数据结构—二叉树的链式结构实现

news2025/2/25 15:13:58

目录

1、建立二叉树

1.1 二叉树的结构

1.2 手动建立二叉树

2、二叉树的遍历

2.1 二叉树的三种遍历方式

2.1.1 前序遍历 

2.1.2 中序遍历

2.1.2 后序遍历

3、求二叉树的结点数和二叉树的高度

3.1 求二叉树结点数

3.2 求二叉树叶子结点

3.3 求二叉树第k层结点的个数

3.4 求二叉树的高度

4、二叉树的查找

1、建立二叉树

在学习二叉树的功能之前,先要建立二叉树,这里我们先手动建立一棵二叉树。

1.1 二叉树的结构

我们要建立的这棵二叉树,将每一个结点表示为一个结构体,每一个结点同时存储了数据和自己子结点的地址(结构体指针),如果没有子结点该指针就指向空。

在这里插入图片描述

typedef int BTDataType;
typedef struct BinaryTreeNode
{
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
}BTNode;

1.2 手动建立二叉树

使用malloc函数为结点分配空间。
为每个结点存储数据。
将新建结点插入数据这个过程封装为函数BuyNode()。

//新建结点
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;
}
// 手动构建一棵二叉树
    BTNode* node1 = BuyNode(1);
    BTNode* node2 = BuyNode(2);
    BTNode* node3 = BuyNode(3);
    BTNode* node4 = BuyNode(4);
    BTNode* node5 = BuyNode(5);
    BTNode* node6 = BuyNode(6);

    node1->left = node2;
    node1->right = node4;
    node2->left = node3;
    node4->left = node5;
    node4->right = node6;

该二叉树示意图:

在这里插入图片描述
2、二叉树的遍历

2.1 二叉树的三种遍历方式

1、前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2、中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之间。
3、后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

二叉树中的核心思想是分治。所谓分治就是分分而治之,大致意思就是将一个复杂的问题转化成一个个简单的小问题,最后解决问题的思想。

2.1.1 前序遍历 

在这里插入图片描述
1、对这棵树进行前序遍历,最原始的方法是
先访问1,然后遍历1左子树。
访问2,遍历2左子树。
访问3,遍历3左子树。
为空,再遍历3右子树。
为空,2的左子树遍历结束,再遍历2的右子树。
为空,1的左子树遍历结束,再遍历1的右子树。
…………
…………
…………
2、根据上述方法,我们可以将这个方法归纳为
先访问1后再前序遍历1的左子树和右子树,
前序遍历A的左子树 可以转化为 先访问2后再前序遍历2的左子树和右子树
前序遍历2的左子树 可以转化为 先访问3后再前序遍历3的左子树和右子树
这样就可以把一个复杂的问题转化为一个个较简单的问题。

void PrevOrder(BTNode* root) 
{
    if (root == NULL) 
    {
        printf("NULL");
        return;
    }

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

2.1.2 中序遍历

在这里插入图片描述
1、对这棵二叉树进行中序遍历,最原始的方法是
先遍历1的左子树。
遍历2的左子树。
遍历3的左子树。
为空,访问3,遍历3的右子树。
为空,访问2,遍历2的右子树。
为空,访问1,遍历1的右子树。
…………
…………
…………
2、根据上述方法,我们可以将这个方法归纳为
中序遍历1的左子树后再访问1,然后中序遍历1的右子树。
中序遍历1的左子树可以转化为中序遍历2的左子树后访问2,然后中序遍历2的右子树。
中序遍历2的右子树又可以转化为中序遍历3的左子树后访问3,然后中序遍历3的右子树。

void InOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return;
    }
    InOrder(root->left);
    printf("%d ", root->data);
    InOrder(root->right);
}

2.1.2 后序遍历

在这里插入图片描述
1、对这颗二叉树进行中序遍历,最原始的方法是
先遍历1的左子树。
遍历2的左子树。
遍历3的左子树。
为空,遍历3的右子树。
为空访,访问3,遍历2的右子树。
为空,访问2,遍历1的右子树。
…………
…………
…………
2、根据上述方法,我们可以将这个方法归纳为
后序遍历1的左子树和右子树后再访问1。
后序遍历1的左子树可以转化为后序遍历2的左子树和右子树后再访问2。
后序遍历2的左子树又可以转化为后序遍历3的左子树和右子树后再访问3。

void PostOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("NULL");
        return;
    }
    PostOrder(root->left);
    PostOrder(root->right);
    printf("%d ", root->data);
}

3、求二叉树的结点数和二叉树的高度

3.1 求二叉树结点数

在这里插入图片描述
解题思路:
1、只要该结点地址不为空就是一个结点。
2、整棵树的结点可以转化成
求1的左子树结点数加1的右子树结点树加1(自己本身也是一个结点)。
1的左子树结点树可以转化成2的左子树结点数加右子树的结点树加1。
2的左子树结点数可以转化成3的左子树结点数加D的右子树结点数加1。
3的左右子树都为空,所以2的左子树结点数为1。
…………
…………
…………
直观的写法:

int TreeSize(BTNode* root)
{
    if (root == NULL)
    {
        return 0;
    }
    return TreeSize(root->left) + TreeSize(root->right) + 1;
}

或者简洁的写法:

int TreeSize(BTNode* root)
{
    return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}


3.2 求二叉树叶子结点

在这里插入图片描述
解题思路:
1、左右孩子结点都为空的结点算作一个叶子节点。
2、求整棵树的叶子结点,可以转化为求1的左子树叶子结点和1的右子树叶子结点。
求1的左子树叶子结点可以转化为求2的左子树叶子结点加2的右子树叶子结点。
3的左右孩子结点都为空,2的左子树叶子节点为1。
…………
…………
…………

int TreeLeafSize(BTNode* root)
{
    if (root == NULL)
        return 0;
    if (root->left == NULL && root->right == NULL)
    {
        return 1;
    }
    return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

3.3 求二叉树第k层结点的个数

在这里插入图片描述
解题思路:
若k为3
1、一棵树的第一层结点为1
2、求这棵树第三层的结点数可以转化为求1的左子树以及1的右子树的第二层结点数之和。
求1的左子树的第二层结点数,可以转化成求2的左子树和2的右子树的第一层结点数之和。
2的左子树不为空,层数为1,结点数为1。
2的右子树为空,结点数为0。
…………
…………
…………

// 第k层的节点个数
int TreeKLevel(BTNode* root, int k)
{
    assert(k > 0);

    if (root == NULL)
        return 0;

    if (k == 1)
    {
        return 1;
    }

    return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);

}

3.4 求二叉树的高度

在这里插入图片描述
解题思路:
1、空树高度为0。
2、一棵树该树的根结点左右子结点都为空时,该树高度为1。
3、一棵树的高度为左右子树中高度较大的一个加1。
4、求图示中树的高度可以转化为1的左右子树中高度较大的一方加1。
求1的左子树高度可以转化为2的左右子树中高度较大的一方加1。
求2的左子树的高度可以转化为3的左右子树中高度较大的一方加1。
3的左右子结点均为空,则2的左子树高度为1。
2的右子树为空树,2的右子树高度为0,
取较大的一方加1,则2的高度为2,即1的左子树高度为2。

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

    if (root->left == NULL && root->right == NULL)
    {
        return 1;
    }

    return max(TreeDepth(root->left), TreeDepth(root->right));
}

4、二叉树的查找

在这里插入图片描述
解题思路:
假设要查找6
如果找到就返回节点地址,没找到返回空。
递归调用的时候要根据返回值来判断是否找到,如果不为空代表找到了,不需要继续查找了,这时返回节点地址。

在整颗树查找6,先看根部是否为6,不是再在1的左右子树中查找。

先看1的左子树根部是否为6,不是再在2的左右子树中查找。

先看2的左子树根部是否为6,不是再在3的左右子树中查找。

3的左右子树为空,返回空。

2的右子树为空,返回空。

1的左子树查找完毕,没找到,查找1的右子树。

先看1的右子树根部是否为6,不是再在4的左右子树查找。
先看4的左子树根部是否为6,不是再在5的左右子树中查找。
5的左右子树为空,返回空。
4的右子树为6,找到了,返回该结点地址。

BTNode* TreeFind(BTNode* root, int x)
{
    if (root == NULL)
        return NULL;

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

    BTNode* ret = NULL;
    ret = TreeFind(root->left, x);
    if (ret)
        return ret;

    ret = TreeFind(root->right, x);
    if (ret)
        return ret;

    return NULL;
}

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

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

相关文章

Java 大视界 —— Java 大数据在智能零售动态定价策略中的应用实战(98)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…

危化品经营单位安全管理人员的职责及注意事项

危化品经营单位安全管理人员肩负着保障经营活动安全的重要责任,以下是其主要职责及注意事项: 职责 1. 安全制度建设与执行:负责组织制定本单位安全生产规章制度、操作规程和生产安全事故应急救援预案,确保这些制度符合国家相关法…

Day 49 卡玛笔记

这是基于代码随想录的每日打卡 1143. 最长公共子序列 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变…

WebXR教学 01 基础介绍

什么是WebXR? 定义 XR VR AR Web上使用XR技术的API WebXR 是一组用于在 Web 浏览器中实现虚拟现实(VR)和增强现实(AR)应用的技术标准。它由 W3C 的 Immersive Web 工作组开发,旨在提供跨设备的沉浸式体验…

DeepSeek+Kimi生成高质量PPT

DeepSeek与Kimi生成PPT全流程解析 一、工具分工原理 DeepSeek核心作用:生成结构化PPT大纲(擅长逻辑构建与内容优化)Kimi核心作用:将文本转换为视觉化PPT(提供模板库与排版引擎) 二、操作步骤详解 1. 通…

clickhouse--表引擎的使用

表引擎决定了如何存储表的数据。包括: 数据的存储方式和位置,写到哪里以及从哪里读取数据。(默认是在安装路径下的 data 路径)支持哪些查询以及如何支持。(有些语法只有在特定的引擎下才能用)并发数据访问。索引的使用&#xff0…

tauri输入js脚本的方法和注意事项initialization_script

注入js脚本最常用的就是initialization_script,通过这个方法注入的js脚本在页面每个页面都会执行,这个在tauri文档也可以搜到:WebviewWindowBuilder in tauri::webview - Rust,但是请注意,这个方法只能用在WindowBuild…

基于springboot的学习社区博客

一、系统架构 前端:html | bootstarp | jquery | css | ajax 后端:springboot | mybatis 环境:jdk1.8 | mysql | maven 二、代码及数据 三、功能介绍 01. web端-注册 02. web端-登录 03. web端-首页 04. web端-文章明…

python-leetcode 42.验证二叉搜索树

题目: 给定二叉树的根节点root,判断是否是一个有效二叉搜索树 有效二叉搜索树: 1.节点的左子树只包含小于当前节点的树 2.节点的右子树只包含大于当前节点的树 3.所有左子树和右子树自身必须也是二叉搜索树 方法一:递归 如果该二叉树的…

基于PSO-LSTM长短期记忆神经网络的多分类预测【MATLAB】

一、研究背景与意义 在时间序列分类、信号识别、故障诊断等领域,多分类预测任务对模型的时序特征捕捉能力提出了极高要求。传统LSTM网络虽能有效建模长程依赖关系,但其性能高度依赖超参数的选择,例如隐含层神经元数量、学习率、迭代次数等。…

拓扑排序的核心算法:BFS应用与实践

目录 一、拓扑排序简介 二、BFS解决拓扑排序的步骤 三、C实现 四、代码解释 五、总结 一、拓扑排序简介 拓扑排序是对有向无环图(DAG)进行排序的一种方法,使得对于图中的每一条有向边 (u, v),u 在排序中总是位于 v 的前面。拓…

Cocos Creator Shader入门实战(一):材质和Effect的了解

引擎版本:3.8.5 环境: Windows 简介 在Cocos Creator中,游戏炫彩缤纷的效果是借助着色器(Shader)来实现的。 Cocos主要基于OpenGL ES,而Shader的编写则是在可编程渲染管线中基于修改:顶点着色器(Vertex) 和 片段着色…

Android 老项目 jcenter 库失效

最近重新维护了一些老项目发现大部分jcenter库失效了, Could not resolve com.xx:2.1.3. 如果你也遇到了,不妨试试 替换为 aliyun的jcenter服务,就不用一个个找代替库了。 project 下的 build.gradle 文件添加: maven { url htt…

2025.2.23机器学习笔记:PINN文献阅读

2025.2.23周报 一、文献阅读题目信息摘要Abstract创新点网络架构架构A架构B架构C 实验结论后续展望 一、文献阅读 题目信息 题目: Physics-Informed Neural Networks for Modeling Water Flows in a River Channel期刊: IEEE TRANSACTIONS ON ARTIFICI…

Python Django系列—入门实例(二)

数据库配置 现在,打开 mysite/settings.py 。这是个包含了 Django 项目设置的 Python 模块。 默认情况下,​ DATABASES 配置使用 SQLite。如果你是数据库新手,或者只是想尝试 Django,这是最简单的选择。SQLite 包含在 Python 中…

【DeepSeek系列】05 DeepSeek核心算法改进点总结

文章目录 一、DeepSeek概要二、4个重要改进点2.1 多头潜在注意力2.2 混合专家模型MoE2.3 多Token预测3.4 GRPO强化学习策略 三、2个重要思考3.1 大规模强化学习3.2 蒸馏方法:小模型也可以很强大 一、DeepSeek概要 2024年~2025年初,DeepSeek …

独立开发者之Google Analytics使用教程

Google Analytics(GA)是Google提供的一款免费的网络分析服务,用于追踪和报告网站流量。以下是独立开发者如何使用Google Analytics的详细教程: 1. 创建Google Analytics账户 注册Google账户:如果你还没有Google账户&…

C++ 编程语言简介

C 是一种通用编程语言,它是作为 C 语言的增强而开发的,以包含面向对象的范例。它是一种命令式和编译语言。 C 是一种高级的通用编程语言,专为系统和应用程序编程而设计。它由贝尔实验室的 Bjarne Stroustrup 于 1983 年开发,作为…

计算机毕业设计SpringBoot+Vue.js明星周边产品销售网站(源码+文档+PPT+讲解)

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…

使用Windbg调试目标进程排查C++软件异常的一般步骤与要点分享

目录 1、概述 2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序 2.1、将Windbg附加到已经启动起来的目标进程上 2.2、用Windbg启动目标程序 2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去 3、分析实例说明 …