【数据结构】栈与队列全方位对比 + C 语言完整实现

前言

栈(Stack)和队列(Queue)是数据结构中最基础、最重要的受限线性表 ,是算法与程序设计的核心基石。二者逻辑结构均为线性结构,仅在操作规则上存在限制,却衍生出完全不同的应用场景。

本文将从核心特性、结构对比、C 语言完整实现、应用场景四个维度,全方位总结栈与队列,配套可直接运行的代码。


一、栈与队列核心概念对比

栈和队列的本质区别是进出规则,这也是记忆和使用的核心:

对比维度 栈 (Stack) 队列 (Queue)
全称 后进先出表 LIFO 先进先出表 FIFO
操作规则 仅在栈顶插入、删除 队尾插入队头删除
生活类比 叠盘子、弹夹 排队买票、电梯
核心指针 栈顶指针 top 队头 front、队尾 rear
核心操作 入栈push、出栈pop 入队enQueue、出队deQueue

二、存储结构对比

栈和队列都支持顺序存储链式存储,适用场景不同:

  1. 顺序存储:基于数组实现,容量固定,访问速度快;
  2. 链式存储:基于链表实现,动态扩容,无空间溢出问题。

三、C 语言完整代码实现(带超详细注释)

1. 顺序栈(数组实现)

固定容量,适合数据规模已知的场景,最简单的栈实现

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100  // 栈最大容量

// 顺序栈结构体定义
typedef struct {
    int data[MAXSIZE];  // 静态数组存储栈元素
    int top;            // 栈顶指针,-1表示空栈
} SqStack;

// 初始化栈
void InitStack(SqStack *s) {
    s->top = -1;
}

// 判断栈是否为空
int IsEmpty(SqStack *s) {
    return s->top == -1;
}

// 入栈操作
int Push(SqStack *s, int val) {
    if(s->top == MAXSIZE-1) {  // 栈满判断
        printf("栈满,入栈失败!\n");
        return 0;
    }
    s->data[++s->top] = val;
    return 1;
}

// 出栈操作
int Pop(SqStack *s, int *val) {
    if(IsEmpty(s)) {  // 栈空判断
        printf("栈空,出栈失败!\n");
        return 0;
    }
    *val = s->data[s->top--];
    return 1;
}

// 获取栈顶元素(不删除)
int GetTop(SqStack *s, int *val) {
    if(IsEmpty(s)) return 0;
    *val = s->data[s->top];
    return 1;
}

// 测试函数
int main() {
    SqStack s;
    InitStack(&s);
    Push(&s, 10);
    Push(&s, 20);
    
    int val;
    Pop(&s, &val);
    printf("出栈元素:%d\n", val);  // 输出20
    GetTop(&s, &val);
    printf("当前栈顶元素:%d\n", val); // 输出10
    return 0;
}

2. 链栈(单链表实现)

动态内存分配,无容量限制,适合数据规模未知的场景

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

// 链栈节点结构体
typedef struct Node {
    int data;           // 数据域
    struct Node *next;  // 指针域
} Node;

// 链栈结构体(仅需栈顶指针)
typedef struct {
    Node *top;
} LinkStack;

// 初始化链栈
void InitStack(LinkStack *s) {
    s->top = NULL;  // 空栈
}

// 入栈(头插法,效率最高)
int Push(LinkStack *s, int val) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    if(!newNode) return 0;
    
    newNode->data = val;
    newNode->next = s->top;  // 新节点指向原栈顶
    s->top = newNode;        // 更新栈顶
    return 1;
}

// 出栈
int Pop(LinkStack *s, int *val) {
    if(s->top == NULL) {
        printf("栈空,出栈失败!\n");
        return 0;
    }
    Node *temp = s->top;
    *val = temp->data;
    s->top = s->top->next;  // 栈顶下移
    free(temp);             // 释放节点
    return 1;
}

// 测试函数
int main() {
    LinkStack s;
    InitStack(&s);
    Push(&s, 10);
    Push(&s, 20);
    
    int val;
    Pop(&s, &val);
    printf("出栈元素:%d\n", val); // 输出20
    return 0;
}

3. 循环队列(数组实现)

解决顺序队列假溢出问题,是顺序队列的最优实现

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 5  // 队列容量

// 循环队列结构体
typedef struct {
    int data[MAXSIZE];
    int front;  // 队头指针
    int rear;   // 队尾指针
} SqQueue;

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

// 判断队列空
int IsEmpty(SqQueue *q) {
    return q->front == q->rear;
}

// 判断队列满(牺牲一个空间区分空/满)
int IsFull(SqQueue *q) {
    return (q->rear + 1) % MAXSIZE == q->front;
}

// 入队
int EnQueue(SqQueue *q, int val) {
    if(IsFull(q)) {
        printf("队列满,入队失败!\n");
        return 0;
    }
    q->data[q->rear] = val;
    q->rear = (q->rear + 1) % MAXSIZE;  // 循环后移
    return 1;
}

// 出队
int DeQueue(SqQueue *q, int *val) {
    if(IsEmpty(q)) {
        printf("队列空,出队失败!\n");
        return 0;
    }
    *val = q->data[q->front];
    q->front = (q->front + 1) % MAXSIZE;
    return 1;
}

// 测试函数
int main() {
    SqQueue q;
    InitQueue(&q);
    EnQueue(&q, 10);
    EnQueue(&q, 20);
    
    int val;
    DeQueue(&q, &val);
    printf("出队元素:%d\n", val); // 输出10
    return 0;
}

4. 链队列(单链表实现)

动态扩容,无容量限制,工业级常用队列实现

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

// 队列节点结构体
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 链队列结构体(队头+队尾指针)
typedef struct {
    Node *front;  // 队头
    Node *rear;   // 队尾
} LinkQueue;

// 初始化(创建头节点)
void InitQueue(LinkQueue *q) {
    q->front = q->rear = (Node*)malloc(sizeof(Node));
    q->front->next = NULL;
}

// 入队
int EnQueue(LinkQueue *q, int val) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = val;
    newNode->next = NULL;
    
    q->rear->next = newNode;
    q->rear = newNode;  // 更新队尾
    return 1;
}

// 出队
int DeQueue(LinkQueue *q, int *val) {
    if(q->front == q->rear) {
        printf("队列空,出队失败!\n");
        return 0;
    }
    Node *temp = q->front->next;
    *val = temp->data;
    q->front->next = temp->next;
    
    // 队列空时,队尾指向头节点
    if(q->rear == temp) q->rear = q->front;
    free(temp);
    return 1;
}

// 测试函数
int main() {
    LinkQueue q;
    InitQueue(&q);
    EnQueue(&q, 10);
    EnQueue(&q, 20);
    
    int val;
    DeQueue(&q, &val);
    printf("出队元素:%d\n", val); // 输出10
    return 0;
}

四、栈与队列核心知识点总结

  1. 共性

    • 均为线性结构,元素一对一排列;
    • 均支持顺序、链式两种存储方式;
    • 均为受限操作的线性表。
  2. 核心差异

    • 栈:后进先出,仅栈顶操作;
    • 队列:先进先出,队头出队、队尾入队。
  3. 选型建议

    • 数据量固定 → 顺序栈 / 循环队列;
    • 数据量动态变化 → 链栈 / 链队列。

五、经典应用场景

栈的应用

  1. 函数调用栈、递归实现
  2. 中缀表达式转后缀表达式、表达式求值
  3. 括号匹配检查
  4. 浏览器前进后退、编辑器撤销操作

队列的应用

  1. 操作系统进程 / 线程调度
  2. 消息队列、缓冲区处理
  3. 广度优先搜索(BFS)
  4. 打印机任务队列
相关推荐
SteveSenna2 小时前
项目:Trossen Arm MuJoCo
人工智能·学习·算法
NAGNIP2 小时前
一文搞懂CNN经典架构-DenseNet!
算法·面试
道法自然|~2 小时前
BugCTF黄道十二宫
算法·密码学
WHS-_-20223 小时前
Python 算法题学习笔记一
python·学习·算法
是苏浙3 小时前
初识集合框架
java·数据结构
沉鱼.443 小时前
第六届题目
算法
黑眼圈子4 小时前
总结一下用Java做算法的常用类和方法
java·开发语言·算法
apcipot_rain4 小时前
天梯赛练习集 时间规划 限时复盘 中档题详解(L1-6~L2-4)
算法
再卷也是菜4 小时前
第一章、线性代数(2)高斯消元法
线性代数·算法