首页/数据结构/03-stack-queue-array/栈和队列的应用 🔗 在 Obsidian 中打开
数据结构 · 03-stack-queue-array

栈和队列的应用

难度 ★★★重要度 ★★★★ 考查频率 高题型 算法 / 简答 括号匹配表达式求值递归层次遍历
速查
栈:括号匹配表达式求值递归(函数调用栈);队列:层次遍历BFS、FCFS 调度。中缀转后缀用运算符栈

核心概念

一、括号匹配

算法思想:遇到左括号入栈,遇到右括号出栈匹配。

bool BracketMatch(char *str) {
    SqStack S; InitStack(&S);
    for (int i = 0; str[i] != '\0'; i++) {
        if (str[i] == '(' || str[i] == '[' || str[i] == '{')
            Push(&S, str[i]);
        else if (str[i] == ')' || str[i] == ']' || str[i] == '}') {
            if (StackEmpty(S)) return false;
            char top; Pop(&S, &top);
            if (str[i] == ')' && top != '(') return false;
            if (str[i] == ']' && top != '[') return false;
            if (str[i] == '}' && top != '{') return false;
        }
    }
    return StackEmpty(S);  // 栈空则匹配成功
}

时间复杂度 O(n),空间复杂度 O(n)。

二、表达式求值

1. 中缀转后缀(逆波兰表达式)

  • 操作数:直接输出
  • 左括号:入栈
  • 右括号:出栈直到遇到左括号
  • 运算符:出栈优先级 $\ge$ 当前的运算符,再将当前运算符入栈

示例 a + b * c + (d * e + f) * g → 后缀 a b c * + d e * f + g * +

2. 后缀表达式求值

操作数入栈;遇运算符弹出两个操作数计算后入栈。例 a b c * +($a=1,b=2,c=3$):$2*3=6\to1+6=7$。

3. 中缀表达式求值(两个栈)

操作数栈 + 运算符栈,按优先级出入栈。

三、递归

递归调用时,系统用函数调用栈保存返回地址、参数、局部变量。可转为显式栈(如斐波那契非递归)。

int Fib(int n) {            // 递归
    if (n == 0 || n == 1) return n;
    return Fib(n-1) + Fib(n-2);
}
int Fib(int n) {            // 非递归(迭代)
    if (n == 0 || n == 1) return n;
    int a = 0, b = 1, c;
    for (int i = 2; i <= n; i++) { c = a + b; a = b; b = c; }
    return c;
}

四、队列的应用

1. 层次遍历(二叉树)

void LevelOrder(BiTree T) {
    Queue Q; InitQueue(&Q); EnQueue(&Q, T);
    while (!QueueEmpty(Q)) {
        BiTNode *p; DeQueue(&Q, &p); visit(p);
        if (p->lchild) EnQueue(&Q, p->lchild);
        if (p->rchild) EnQueue(&Q, p->rchild);
    }
}

2. BFS(广度优先搜索)

void BFS(Graph G, int v) {
    visit(v); visited[v] = true; EnQueue(&Q, v);
    while (!QueueEmpty(Q)) {
        DeQueue(&Q, &v);
        for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w))
            if (!visited[w]) { visit(w); visited[w] = true; EnQueue(&Q, w); }
    }
}

3. 操作系统中的应用

  • FCFS 调度(先来先服务)
  • 打印任务队列
  • 消息队列

手算示例

例 1:中缀转后缀

表达式 A + B * (C - D) - E / F,逐步得到后缀 A B C D - * + E F / -

例 2:后缀表达式求值

后缀 3 4 + 5 × 6 - → $3+4=7\to7\times5=35\to35-6=29$。结果 29

常见考法

高频设问
  • 中缀转后缀:手写转换过程。
  • 后缀求值:给出后缀与操作数值求结果。
  • 括号匹配:写出算法思路与代码。
  • 递归与栈:栈保存返回地址、参数、局部变量。

易错点

必记
  1. 优先级* / 高于 + -( 入栈后优先级最低。
  2. 同级运算符:左结合,先出栈再入栈。
  3. 后缀求值顺序:先弹出的是右操作数(减/除不可交换)。
  4. 括号处理( 入栈,) 出栈直到 (
  5. 递归深度:有栈溢出风险。

核心结论

必背
  1. 括号匹配:O(n) 时间,O(n) 空间。
  2. 中缀转后缀:运算符栈按优先级出入栈。
  3. 后缀求值:操作数栈,遇运算符弹两个计算。
  4. 递归:系统用栈实现,可转显式栈。

记忆卡片

括号匹配时间复杂度?
O(n),每元素最多入栈出栈各一次。
中缀转后缀遇右括号?
出栈直到遇到左括号(左括号也出栈但不输出)。
后缀求值:操作数入栈还是出栈?
操作数入栈,遇运算符弹两个计算后入栈。
递归调用系统保存什么?
函数调用栈:返回地址、参数、局部变量。
二叉树层次遍历用什么?
队列(FIFO,符合层次顺序)。
后缀求值先弹出的是左还是右操作数?
右操作数(减/除顺序敏感)。

交互动画 · 中缀转后缀

输入 输出(后缀) 运算符栈
表达式 A + B * (C - D) - E / F → 后缀
点击「播放」或「下一步」逐步演示
橙色 = 已处理;右侧栈顶在上。同级运算符先弹出再压入。

相关知识点

stack-basic-operations queue-basic-operations stack-and-queue-applications

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。