数据结构:从队列到二叉树基础解析

这章讲解了队列的知识,树形结构的基本概念,以及二叉树的基础部分以及相关的概念,例如根据前序和中序,计算后序等

从队列到二叉树 数据结构入门核心脉络解析

今天我们从两个经典数据结构入手 队列和二叉树 串联讲解它们的核心概念与应用 尤其会深入剖析二叉树中前序中序求后序的经典问题 让你彻底搞懂递归与树的逻辑

一 队列 先进先出的线性表

1 什么是队列

队列是一种线性数据结构 特点是先进先出FIFO 像生活中排队买票 先来的人先买到票离开 后来的人排在队尾 队列有两个关键端 队头出队 队尾入队

2 基本操作

入队enqueue 在队尾添加元素 出队dequeue 在队头移除元素 判空isEmpty 判断队列是否有元素 判满isFull 判断队列是否已满

3 实现 循环数组队列

用数组实现队列时 为避免假溢出 常用循环数组 即数组首尾相连 用两个指针front队头 rear队尾标记位置

cpp 复制代码
#include <stdio.h>
#define MAX_SIZE 5  // 队列最大容量

// 队列结构体
typedef struct {
    int data[MAX_SIZE];  // 存储元素的数组
    int front;           // 队头指针 指向队头元素
    int rear;            // 队尾指针 指向队尾下一个位置
} Queue;

// 初始化队列
void initQueue(Queue *q) {
    q->front = 0;
    q->rear = 0;
}

// 判空 队头队尾重合且未存元素时为空
int isEmpty(Queue *q) {
    return q->front == q->rear;
}

// 判满 队尾下一个位置是队头时满 (循环)
int isFull(Queue *q) {
    return (q->rear + 1) % MAX_SIZE == q->front;
}

// 入队
int enqueue(Queue *q, int val) {
    if (isFull(q)) {
        printf("队列已满 无法入队\n");
        return 0;  // 失败
    }
    q->data[q->rear] = val;
    q->rear = (q->rear + 1) % MAX_SIZE;  // 队尾循环后移
    return 1;  // 成功
}

// 出队
int dequeue(Queue *q, int *val) {
    if (isEmpty(q)) {
        printf("队列为空 无法出队\n");
        return 0;  // 失败
    }
    *val = q->data[q->front];
    q->front = (q->front + 1) % MAX_SIZE;  // 队头循环后移
    return 1;  // 成功
}

// 示例 模拟排队
void queueExample() {
    Queue q;
    initQueue(&q);
    enqueue(&q, 10);  // 队尾入队10
    enqueue(&q, 20);  // 入队20
    enqueue(&q, 30);  // 入队30
    int val;
    dequeue(&q, &val);  // 队头出队10
    printf("出队元素 %d\n", val);  // 输出10
    enqueue(&q, 40);
    enqueue(&q, 50);
    enqueue(&q, 60);  // 此时队列满 无法入队
}

二 树形结构基本概念

1 什么是树

树是非线性数据结构 像倒过来的树 有根节点 每个节点有零个或多个子节点 子节点下还有子树 最上面是根 最下面是叶子

2 核心术语

节点 树的基本单位 度 节点拥有的子节点数 叶子节点 度为0的节点 双亲 父节点 孩子 子节点 兄弟 同一双亲的子节点 层次 根是第一层 往下递增 深度 树的最大层次 森林 多棵互不相交的树

3 例子

家族树 根是祖先 孩子是后代 公司架构 根是CEO 子树是各部门

三 二叉树基础

1 定义

二叉树是每个节点最多有两棵子树的树 分别叫左子树和右子树 子树有顺序 不能颠倒

2 特殊二叉树

满二叉树 每层节点都满 深度k有2^k 1个节点 完全二叉树 除最后一层 其余层满 最后一层节点靠左排列

3 性质

第i层最多有2^i 1个节点 深度为k的二叉树最多有2^k 1个节点 对任意二叉树 叶子数 度为2的节点数 1

4 遍历方式

前序遍历 根左右 先访问根 再左子树 再右子树 中序遍历 左根右 先左子树 再根 再右子树 后序遍历 左右根 先左子树 再右子树 再根 层序遍历 按层次从左到右访问

cpp 复制代码
// 二叉树节点结构体
typedef struct TreeNode {
    int val;                // 节点值
    struct TreeNode *left;  // 左子树
    struct TreeNode *right; // 右子树
} TreeNode;

// 前序遍历 根左右
void preorder(TreeNode *root) {
    if (root == NULL) return;
    printf("%d ", root->val);  // 访问根
    preorder(root->left);      // 左子树
    preorder(root->right);     // 右子树
}

// 中序遍历 左根右
void inorder(TreeNode *root) {
    if (root == NULL) return;
    inorder(root->left);       // 左子树
    printf("%d ", root->val);  // 访问根
    inorder(root->right);      // 右子树
}

// 后序遍历 左右根
void postorder(TreeNode *root) {
    if (root == NULL) return;
    postorder(root->left);     // 左子树
    postorder(root->right);    // 右子树
    printf("%d ", root->val);  // 访问根
}

四 前序中序求后序 递归的艺术

问题引入

已知二叉树前序序列和中序序列 求后序序列 例 前序ABDECF 中序DBEAFC 求后序

核心思路

前序定根 中序分左右 递归求解

步骤

1 前序第一个元素是根节点

2 在中序中找到根 左边是左子树中序 右边是右子树中序

3 根据左子树节点数 在前序中划分左子树前序右子树前序

4 递归处理左子树 得左后序 递归处理右子树 得右后序

5 后序 左后序 + 右后序 + 根

代码实现
cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 根据前序pre和中序in 求后序 返回后序字符串
char* preInToPost(char *pre, char *in, int len) {
    if (len <= 0) {  // 空树
        char *post = (char*)malloc(1);
        post[0] = '\0';
        return post;
    }

    char root = pre[0];  // 前序首元素为根
    // 在中序中找根位置
    int i;
    for (i = 0; i < len; i++) {
        if (in[i] == root) break;
    }  // i是根在中序的位置

    int leftLen = i;         // 左子树节点数
    int rightLen = len - i - 1;  // 右子树节点数

    // 递归左子树 前序[1~leftLen] 中序[0~i-1]
    char *leftPost = preInToPost(pre + 1, in, leftLen);
    // 递归右子树 前序[1+leftLen~end] 中序[i+1~end]
    char *rightPost = preInToPost(pre + 1 + leftLen, in + i + 1, rightLen);

    // 拼接后序 左后序+右后序+根
    char *post = (char*)malloc(len + 1);
    strcpy(post, leftPost);
    strcat(post, rightPost);
    post[len - 1] = root;  // 根放最后
    post[len] = '\0';

    free(leftPost);  // 释放临时内存
    free(rightPost);
    return post;
}

// 示例
void example() {
    char pre[] = "ABDECF";  // 前序
    char in[] = "DBEAFC";   // 中序
    int len = strlen(pre);
    char *post = preInToPost(pre, in, len);
    printf("后序序列 %s\n", post);  // 输出DEBFCA
    free(post);
}
变体思考

中序后序求前序 思路类似 后序末元素为根 中序分左右 递归求左右前序 拼接根+左前序+右前序

总结

队列教会我们线性结构的顺序管理 二叉树则打开非线性思维大门 前序中序求后序的核心是递归拆分 抓住根与左右子树的关系 多画图多练手 就能掌握树的逻辑 动手实现这些代码 你会发现数据结构并不难

相关推荐
一匹电信狗2 小时前
【高阶数据结构】并查集
c语言·数据结构·c++·算法·leetcode·排序算法·visual studio
进击的小头2 小时前
设计模式组合应用:传感器数据采集与处理系统
c语言·设计模式
愚者游世2 小时前
list Initialization各版本异同
开发语言·c++·学习·程序人生·算法
.小墨迹2 小时前
apollo中车辆的减速绕行,和加速超车实现
c++·学习·算法·ubuntu·机器学习
日拱一卒——功不唐捐2 小时前
01背包(C语言)
c语言
超级大只老咪2 小时前
DFS算法(回溯搜索)
算法
MicroTech20252 小时前
量子仿真新基石:MLGO微算法科技专用地址生成器驱动量子算法仿真革命
科技·算法·量子计算
Hello World . .2 小时前
数据结构:二叉树(Binary tree)
c语言·开发语言·数据结构·vim
WBluuue2 小时前
数据机构与算法:dp优化——倍增优化
c++·算法·leetcode·动态规划