跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C算法

数据结构:二叉树基础概念与 C 语言实现

二叉树是一种非线性数据结构,每个结点最多有两个子树。系统讲解二叉树的定义、术语、性质及特殊形态(满二叉树、完全二叉树)。重点阐述链式存储结构的 C 语言实现,包括创建、前中后序遍历、层序遍历(基于队列)、节点统计、高度计算、查找及完全性判断。内容涵盖核心算法逻辑与完整工程代码结构,适合希望深入理解树形结构及递归应用的开发者。

怪力乱神发布于 2026/3/23更新于 2026/5/65 浏览
数据结构:二叉树基础概念与 C 语言实现

数据结构:二叉树基础概念与 C 语言实现

一、树是什么?

1. 树的定义

树是一种非线性数据结构,由 n(n>=0)个有限结点组成一个具有层次关系的集合。

  • 根结点:有一个特殊的结点,没有前驱结点。
  • 子树:除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1、T2……Tm,每一个集合 Ti 又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有 0 个或多个后继。

2. 常见术语

  • 结点的度:一个结点含有的子树的个数。
  • 叶结点:度为 0 的结点。
  • 双亲结点:若一个结点含有子结点,则这个结点称为其子结点的父结点。
  • 子结点:一个结点含有的子树的根结点称为该结点的子结点。
  • 树的高度或深度:树中结点的最大层次。

二、二叉树

1. 二叉树的概念

二叉树是一种特殊的树,其树的度最大为 2。也就是说,一个结点最多有两个分叉。在实际应用中,由于普通树结构复杂,最实用的是二叉树。

2. 二叉树的组成

二叉树由一个根结点加上两棵别称为左子树和右子树的二叉树组成。注意二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树。

3. 特殊的二叉树

  • 满二叉树:一个二叉树,如果每一层的结点数都达到最大值,则这个二叉树就是满二叉树。如果层数为 K,且结点总数是 2^K - 1,则它是满二叉树。
  • 完全二叉树:对于深度为 K 的、有 n 个结点的二叉树,当且仅当其每一个结点都与深度为 K 的满二叉树中编号从 1 至 n 的结点一一对应时称之为完全二叉树。满二叉树是一种特殊的完全二叉树。

4. 二叉树的顺序存储

对于完全二叉树,由于其编号是连续的,可以用数组进行存储。物理上是一个数组,逻辑上是一颗二叉树。

5. 二叉树的性质

  1. 若规定根结点的层数为 1,则一棵非空二叉树的第 i 层上最多有 2^(i-1) 个结点。
  2. 若规定根结点的层数为 1,则深度为 h 的二叉树的最大结点数是 2^h - 1。
  3. 对任何一棵二叉树,如果度为 0 的叶结点个数为 n₀,度为 2 的分支结点个数为 n₂,则有 n₀ = n₂ + 1。
  4. 若规定根结点的层数为 1,具有 n 个结点的满二叉树的深度 h = log₂(n + 1)。
  5. 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从 0 开始编号,存在以下关系:
    • 若父亲在数组中下标为 i,则该父亲的左孩子下标为 2 * i + 1,右孩子下标为 2 * i + 2。
    • 若孩子在数组中下标为 i,则该孩子的父亲下标为 (i - 1) / 2。 (注:前提是这些下标所对应的值存在)

三、二叉树的实现

1. 链式存储

前面提到完全二叉树可以用数组存储,但非完全二叉树若强行用数组会浪费大量空间。因此通常采用链式存储,即创建链表,使每个结点由三个域组成:数据域和左右指针域。左右指针分别用来给出该结点左孩子和右孩子所在结点的地址。

2. 节点定义

与单链表类似,二叉树中的每一个节点有以下三个成员:

  1. 节点中存储的数据
  2. 指向节点左孩子的指针
  3. 指向节点右孩子的指针

为了便于类型修改,我们使用 typedef 重定义数据类型。

// BTNode.h
#pragma once


  BTDataType;

 
    BTDataType data;
    
    
} BTNode;
#include "Queue.h"
typedef
char
typedef
struct BinaryTreeNode {
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;

3. 构建二叉树

这里通过一个前序遍历的数组来构建二叉树。例如 "ABD##E#H##CF##G##",其中 # 表示空节点。

// BTNode.c
BTNode* BinaryTreeCreate(BTDataType* ch, int* pi) {
    if (ch[*pi] == '#') {
        return NULL;
    }
    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    if (newnode == NULL) {
        perror("malloc fail");
        return NULL;
    }
    newnode->data = ch[(*pi)++];
    newnode->left = BinaryTreeCreate(ch, pi);
    (*pi)++;
    newnode->right = BinaryTreeCreate(ch, pi);
    return newnode;
}

4. 二叉树遍历

遍历主要有四种:前序、中序、后序、层序。核心在于递归处理左右子树的顺序不同。

前序遍历

先遍历根,接着左子树,最后右子树。

void BinaryTreePrevOrder(BTNode* root) {
    if (root == NULL) {
        return;
    }
    printf("%c ", root->data);
    BinaryTreePrevOrder(root->left);
    BinaryTreePrevOrder(root->right);
}
中序遍历

先遍历左子树,接着根,最后右子树。

void BinaryTreeInOrder(BTNode* root) {
    if (root == NULL) {
        return;
    }
    BinaryTreeInOrder(root->left);
    printf("%c ", root->data);
    BinaryTreeInOrder(root->right);
}
后序遍历

先遍历右子树,接着左子树,最后根。

void BinaryTreePostOrder(BTNode* root) {
    if (root == NULL) {
        return;
    }
    BinaryTreePostOrder(root->left);
    BinaryTreePostOrder(root->right);
    printf("%c ", root->data);
}
层序遍历

一层一层地遍历。这需要借助队列来实现。每次取出队头结点,将其左右孩子入队。

void BinaryTreeLevelOrder(BTNode* root) {
    Queue Q;
    QueueInit(&Q);
    if (root) {
        QueuePush(&Q, root);
    }
    while (!QueueEmpty(&Q)) {
        BTNode* front = QueueFront(&Q);
        printf("%c ", front->data);
        QueuePop(&Q);
        if (front->left) {
            QueuePush(&Q, front->left);
        }
        if (front->right) {
            QueuePush(&Q, front->right);
        }
    }
    QueueDestroy(&Q);
}

5. 其他常用操作

节点个数计算

递归计算左右子树节点数并加 1。

int BinaryTreeSize(BTNode* root) {
    return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
二叉树高度计算

返回左右子树高度较高的一边加 1。

int BinaryTreeHight(BTNode* root) {
    if (root == NULL) {
        return 0;
    }
    return fmax(BinaryTreeHight(root->left), BinaryTreeHight(root->right)) + 1;
}
第 k 层节点个数计算

初始 k,若未到目标层则 k-1 并递归左右子树。

int BinaryTreeLevelKSize(BTNode* root, int k) {
    if (root == NULL) {
        return 0;
    }
    if (k == 1) {
        return 1;
    }
    return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
查找值为 x 的节点

递归查找,注意返回值传递。

BTNode* BinaryTreeFind(BTNode* root, BTDataType x) {
    if (root == NULL) {
        return NULL;
    }
    if (root->data == x) {
        return root;
    }
    BTNode* ret1 = BinaryTreeFind(root->left, x);
    if (ret1) {
        return ret1;
    }
    BTNode* ret2 = BinaryTreeFind(root->right, x);
    if (ret2) {
        return ret2;
    }
    return NULL;
}
判断是否是完全二叉树

利用层序遍历,遇到空节点后若还有非空节点,则不是完全二叉树。

int BinaryTreeComplete(BTNode* root) {
    Queue Q;
    QueueInit(&Q);
    if (root) {
        QueuePush(&Q, root);
    }
    while (!QueueEmpty(&Q)) {
        BTNode* front = QueueFront(&Q);
        QueuePop(&Q);
        if (front == NULL) {
            break;
        }
        QueuePush(&Q, front->left);
        QueuePush(&Q, front->right);
    }
    while (!QueueEmpty(&Q)) {
        BTNode* front = QueueFront(&Q);
        QueuePop(&Q);
        if (front != NULL) {
            QueueDestroy(&Q);
            return 0;
        }
    }
    QueueDestroy(&Q);
    return 1;
}

四、完整代码结构

工程通常分为头文件和源文件,以管理依赖和编译。

1. Queue.h & Queue.c

用于实现队列辅助层序遍历。注意包含标准库头文件如 <stdio.h>、<stdlib.h> 等,替换原文件中可能存在的拼写错误(如 sperror.h)。

2. Test.c

测试用例示例。

#include "BTNode.h"

int main() {
    char ch[100] = "ABD##E#H##CF##G##";
    int i = 0;
    BTNode* T = BinaryTreeCreate(ch, &i);

    printf("节点个数:%d\n", BinaryTreeSize(T));
    printf("叶子节点个数:%d\n", BinaryTreeLeafSize(T));
    printf("高度:%d\n", BinaryTreeHight(T));
    printf("第 3 层节点个数:%d\n", BinaryTreeLevelKSize(T, 3));

    BTNode* ret = BinaryTreeFind(T, 'G');
    if (ret) {
        printf("找到 G: %c\n", ret->data);
    } else {
        printf("未找到\n");
    }

    printf("是否完全二叉树:%s\n", BinaryTreeComplete(T) ? "是" : "否");

    printf("前序:");
    BinaryTreePrevOrder(T);
    printf("\n");
    printf("中序:");
    BinaryTreeInOrder(T);
    printf("\n");
    printf("后序:");
    BinaryTreePostOrder(T);
    printf("\n");
    printf("层序:");
    BinaryTreeLevelOrder(T);
    printf("\n");

    BinaryTreeDestory(&T);
    return 0;
}

本文涵盖了二叉树的核心知识点与工程化实现细节。理解递归思想是掌握二叉树的关键,实际开发中建议多动手调试代码,观察栈帧变化与指针指向,从而建立直观的空间模型。

目录

  1. 数据结构:二叉树基础概念与 C 语言实现
  2. 一、树是什么?
  3. 1. 树的定义
  4. 2. 常见术语
  5. 二、二叉树
  6. 1. 二叉树的概念
  7. 2. 二叉树的组成
  8. 3. 特殊的二叉树
  9. 4. 二叉树的顺序存储
  10. 5. 二叉树的性质
  11. 三、二叉树的实现
  12. 1. 链式存储
  13. 2. 节点定义
  14. 3. 构建二叉树
  15. 4. 二叉树遍历
  16. 前序遍历
  17. 中序遍历
  18. 后序遍历
  19. 层序遍历
  20. 5. 其他常用操作
  21. 节点个数计算
  22. 二叉树高度计算
  23. 第 k 层节点个数计算
  24. 查找值为 x 的节点
  25. 判断是否是完全二叉树
  26. 四、完整代码结构
  27. 1. Queue.h & Queue.c
  28. 2. Test.c
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • PyQt5 高级界面开发:菜单工具栏与布局管理
  • Qwen-Image-2512 V2 模型特性与 ComfyUI/WebUI 部署指南
  • Prompt 编写的日志分析与关键字聚类
  • 黑客和渗透测试基础知识及书籍推荐
  • 二分查找实战:山峰数组峰顶索引与寻找峰值解析
  • 基于 SpringBoot 的图书租借系统设计与实现
  • AI 驱动对话式 PCB 设计工具效率与边界分析
  • Dify 私有化部署教程:搭建专属 AI 知识库平台
  • ZeroClaw Gateway + LM Studio + Reflex 本地 AI 管理面板搭建
  • Spec Kit:GitHub 官方推出的规范驱动开发工具包
  • ComfyUI Photoshop 插件配置与 AI 绘画工作流实战
  • Linux 系统安装、卸载与更新 Node.js 及 Git 指南
  • 大模型微调七步法:构建垂直领域专用模型
  • 基于小米 9 手机搭建天马 G 复古掌机前端
  • Spring Boot 集成 ECharts 实现数据可视化实战
  • Python 调用本地 DocsGPT API 构建 GUI 开发工具
  • 深入详解组合数学:理解组合问题在 AI 算法中的应用
  • OpenClaw WebUI 空白页问题修复指南
  • 基于 YOLO26 深度学习的无人机视角车辆旋转框检测系统
  • LeetCode Hot 100 链表进阶:反转与排序实战 (Python)

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online