CCF-CSP备战NO.6【栈】

一、括号匹配

输入 {\[\]}()

输出 true

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    
    stack<char> stk;
    bool valid = true;
    
    for (char c : s) {
        if (c == '(' || c == '[' || c == '{') {
            stk.push(c);
        } else {
            if (stk.empty()) {
                valid = false;
                break;
            }
            char top = stk.top();
            stk.pop();
            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                valid = false;
                break;
            }
        }
    }
    
    if (!stk.empty()) valid = false;
    
    cout << (valid ? "true" : "false") << endl;
    
    return 0;
}

变式1 最长有效括号子串长度❌

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    
    stack<int> stk;
    stk.push(-1);  // 哨兵,方便计算长度
    int maxLen = 0;
    
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == '(') {
            stk.push(i);
        } else {
            stk.pop();
            if (stk.empty()) {
                stk.push(i);  // 重新设置起点
            } else {
                maxLen = max(maxLen, i - stk.top());
            }
        }
    }
    
    cout << maxLen << endl;
    return 0;
}

变式2 括号匹配 + 得分计算❌

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    
    stack<int> left, star;
    
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == '(') {
            left.push(i);
        } else if (s[i] == '*') {
            star.push(i);
        } else {
            if (!left.empty()) {
                left.pop();
            } else if (!star.empty()) {
                star.pop();
            } else {
                cout << "false" << endl;
                return 0;
            }
        }
    }
    
    // 处理剩余的左括号
    while (!left.empty() && !star.empty()) {
        if (left.top() > star.top()) {
            cout << "false" << endl;
            return 0;
        }
        left.pop();
        star.pop();
    }
    
    cout << (left.empty() ? "true" : "false") << endl;
    return 0;
}

变式3 多括号 + 通配符☑️

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    
    stack<int> left, star;
    
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == '(') {
            left.push(i);
        } else if (s[i] == '*') {
            star.push(i);
        } else {
            if (!left.empty()) {
                left.pop();
            } else if (!star.empty()) {
                star.pop();
            } else {
                cout << "false" << endl;
                return 0;
            }
        }
    }
    
    // 处理剩余的左括号
    while (!left.empty() && !star.empty()) {
        if (left.top() > star.top()) {
            cout << "false" << endl;
            return 0;
        }
        left.pop();
        star.pop();
    }
    
    cout << (left.empty() ? "true" : "false") << endl;
    return 0;
}

变式4 HTML标签匹配(简单版本)☑️

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    string s;
    getline(cin, s);  // 读取整行,因为 HTML 里有空格
    
    stack<string> stk;  // 存标签名,比如 "div"、"p"
    int i = 0;
    bool valid = true;
    
    while (i < s.length()) {
        if (s[i] == '<') {          // 遇到 < 说明开始了一个标签
            int j = i + 1;          // j 指向 < 后面的第一个字符
            
            bool isEnd = (s[j] == '/');  // 判断是不是结束标签 </xxx>
            if (isEnd) j++;              // 如果是 </,跳过 /
            
            // 找到标签名的结尾(遇到 > 为止)
            while (j < s.length() && s[j] != '>') j++;
            
            // 提取标签名
            string tag = s.substr(
                isEnd ? i + 2 : i + 1,   // 起始位置
                j - i - 1 - isEnd        // 长度
            );
            
            if (isEnd) {
                // 遇到结束标签 </tag>
                if (stk.empty() || stk.top() != tag) {
                    valid = false;  // 栈空或栈顶不匹配 → 非法
                    break;
                }
                stk.pop();  // 匹配成功,弹出
            } else {
                // 遇到开始标签 <tag>
                stk.push(tag);
            }
            
            i = j + 1;  // 跳到 > 后面继续处理
        } else {
            i++;  // 普通字符跳过
        }
    }
    
    if (!stk.empty()) valid = false;  // 栈里还有没匹配的开始标签
    
    cout << (valid ? "true" : "false") << endl;
    return 0;
}

二、单调栈

模板 下一个更大元素

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int nums[N], ans[N], stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> nums[i];
    
    // 从右往左遍历
    for (int i = n; i >= 1; i--) {
        // 弹出所有比当前元素小的栈顶元素(它们不可能成为左边元素的答案)
        while (tt > 0 && stk[tt] <= nums[i]) tt--;
        
        // 栈空说明右边没有更大的,否则栈顶就是答案
        ans[i] = (tt > 0) ? stk[tt] : -1;
        
        // 当前元素入栈
        stk[++tt] = nums[i];
    }
    
    for (int i = 1; i <= n; i++) cout << ans[i] << " ";
    return 0;
}

变式1 下一个更大元素 II(循环数组)

题目描述

给定一个循环数组 nums(最后一个元素的下一个是第一个元素),找出每个元素右边第一个比它大的元素。

样例

复制代码
输入: [1, 2, 1]
输出: [2, -1, 2]
解释:
- 1 右边第一个比它大的是 2
- 2 右边没有更大的,输出 -1
- 1 右边第一个比它大的是 2(因为是循环数组)

核心思路

把数组复制一份接在后面,遍历 2n 个元素,用 i % n 映射回原数组。

代码01

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 200010;
int nums[N], ans[N], stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> nums[i];
    
    // 从右向左遍历 2n 个元素
    for (int i = 2 * n - 1; i >= 0; i--) {
        int idx = i % n;
        
        // 单调递减栈
        while (tt > 0 && stk[tt] <= nums[idx]) tt--;
        
        // 只在第一轮(i < n)时记录答案
        if (i < n) {
            ans[idx] = (tt > 0) ? stk[tt] : -1;
        }
        
        stk[++tt] = nums[idx];
    }
    
    for (int i = 0; i < n; i++) cout << ans[i] << " ";
    return 0;
}

代码02

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 200010;
int nums[N], ans[N], stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
        ans[i] = -1;  // 初始化为 -1
    }
    
    // 遍历 2n 个元素,模拟循环数组
    for (int i = 0; i < 2 * n; i++) {
        int idx = i % n;  // 映射回原数组索引
        
        // 栈里存的是索引,不是值
        while (tt > 0 && nums[stk[tt]] < nums[idx]) {
            ans[stk[tt]] = nums[idx];  // 当前元素是栈顶元素的答案
            tt--;
        }
        
        stk[++tt] = idx;
    }
    
    for (int i = 0; i < n; i++) cout << ans[i] << " ";
    return 0;
}

变式2 每日温度

题目描述

给定一个温度列表 temperatures,对于每一天,输出要等多少天才会出现更高的温度。如果没有,输出 0。

样例

复制代码
输入: [73, 74, 75, 71, 69, 72, 76, 73]
输出: [1, 1, 4, 2, 1, 1, 0, 0]
解释:
- 第 1 天 73℃,第 2 天 74℃ → 等 1 天
- 第 3 天 75℃,第 7 天 76℃ → 等 4 天
- 第 7 天 76℃,后面没有更高的 → 0

核心思路

栈里存索引,遇到比栈顶大的元素就弹出并计算天数差。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int temps[N], ans[N], stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> temps[i];
    
    for (int i = 1; i <= n; i++) {
        // 当前温度比栈顶温度高 → 栈顶的答案就是当前天数
        while (tt > 0 && temps[stk[tt]] < temps[i]) {
            ans[stk[tt]] = i - stk[tt];
            tt--;
        }
        stk[++tt] = i;
    }
    
    // 栈里剩下的元素,答案都是 0(已经初始化为 0)
    for (int i = 1; i <= n; i++) cout << ans[i] << " ";
    return 0;
}

变式3 柱状图中最大的矩形

题目描述

给定 n 个非负整数,表示柱状图中各个柱子的高度,每个柱子宽度为 1。求该柱状图中能够勾勒出的矩形的最大面积。

样例

复制代码
输入: [2, 1, 5, 6, 2, 3]
输出: 10
解释: 高度为 5 和 6 的柱子可以组成 5×2=10 的矩形

核心思路

  • 对于每根柱子,找到它左边第一个比它矮的和右边第一个比它矮的

  • 这两根柱子之间的宽度 × 当前高度 = 以当前高度为高的最大矩形面积

  • 用单调栈一次遍历找到左右边界

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int heights[N], stk[N], tt = 0;
int leftSmall[N], rightSmall[N];

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> heights[i];
    
    // 找左边第一个比当前矮的柱子
    for (int i = 1; i <= n; i++) {
        while (tt > 0 && heights[stk[tt]] >= heights[i]) tt--;
        leftSmall[i] = tt > 0 ? stk[tt] : 0;  // 0 表示左边没有更矮的
        stk[++tt] = i;
    }
    
    // 清空栈,找右边第一个比当前矮的柱子
    tt = 0;
    for (int i = n; i >= 1; i--) {
        while (tt > 0 && heights[stk[tt]] >= heights[i]) tt--;
        rightSmall[i] = tt > 0 ? stk[tt] : n + 1;  // n+1 表示右边没有更矮的
        stk[++tt] = i;
    }
    
    long long maxArea = 0;
    for (int i = 1; i <= n; i++) {
        long long width = rightSmall[i] - leftSmall[i] - 1;
        long long area = width * heights[i];
        maxArea = max(maxArea, area);
    }
    
    cout << maxArea << endl;
    return 0;
}

变式4 接雨水

题目描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

样例

复制代码
输入: [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
输出: 6

核心思路

用单调递减栈,遇到比栈顶高的柱子时,说明可以形成凹槽接水。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int height[N], stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> height[i];
    
    int totalWater = 0;
    
    for (int i = 1; i <= n; i++) {
        // 当前高度比栈顶高 → 可以接水
        while (tt > 0 && height[stk[tt]] < height[i]) {
            int bottom = height[stk[tt]];  // 底部高度
            tt--;
            
            if (tt == 0) break;  // 左边没有墙了
            
            int left = stk[tt];  // 左边界的索引
            int h = min(height[left], height[i]) - bottom;  // 水的高度
            int w = i - left - 1;  // 水的宽度
            totalWater += h * w;
        }
        stk[++tt] = i;
    }
    
    cout << totalWater << endl;
    return 0;
}

三、出入栈合法性

模板题目

题目描述

给定一个入栈序列 pushSeq 和一个出栈序列 popSeq,判断 popSeq 是否可能是 pushSeq 的一个合法出栈序列。

约束

  • 入栈序列是 1, 2, 3, ..., n(按顺序入栈)

  • 出栈序列是一个 1~n 的排列

  • 栈可以随时出栈,但必须遵循 LIFO 规则

样例

复制代码
输入:
n = 5
popSeq = [4, 5, 3, 2, 1]

输出: Yes
解释:
1 入栈 → 栈: [1]
2 入栈 → 栈: [1, 2]
3 入栈 → 栈: [1, 2, 3]
4 入栈 → 栈: [1, 2, 3, 4]
4 出栈 → 栈: [1, 2, 3]          → 出栈序列第一个是 4 ✓
5 入栈 → 栈: [1, 2, 3, 5]
5 出栈 → 栈: [1, 2, 3]          → 出栈序列第二个是 5 ✓
3 出栈 → 栈: [1, 2]             → 出栈序列第三个是 3 ✓
2 出栈 → 栈: [1]                → 出栈序列第四个是 2 ✓
1 出栈 → 栈: []                 → 出栈序列第五个是 1 ✓

输入:
n = 5
popSeq = [3, 1, 2, 4, 5]

输出: No
解释:
1 入栈 → 栈: [1]
2 入栈 → 栈: [1, 2]
3 入栈 → 栈: [1, 2, 3]
3 出栈 → 栈: [1, 2]            → 出栈序列第一个是 3 ✓
接下来要出 1,但栈顶是 2,1 被压在下面 → 不可能

完整代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    
    vector<int> popSeq(n);
    for (int i = 0; i < n; i++) cin >> popSeq[i];
    
    int current = 0;  // 当前要匹配的出栈序列索引
    bool valid = true;
    
    // 按顺序让 1~n 入栈
    for (int i = 1; i <= n; i++) {
        stk[++tt] = i;  // i 入栈
        
        // 只要栈不空且栈顶等于当前要出栈的元素,就出栈
        while (tt > 0 && stk[tt] == popSeq[current]) {
            tt--;
            current++;
        }
    }
    
    // 如果所有元素都成功出栈,说明序列合法
    if (current == n) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    
    return 0;
}

变式 1:入栈序列不是 1~n

题目

给定任意入栈序列 pushSeq 和出栈序列 popSeq,判断是否合法。

代码改动 :只需要把 for (int i = 1; i <= n; i++) 改成遍历 pushSeq 即可。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int stk[N], tt = 0;

int main() {
    int n;
    cin >> n;
    
    vector<int> pushSeq(n), popSeq(n);
    for (int i = 0; i < n; i++) cin >> pushSeq[i];
    for (int i = 0; i < n; i++) cin >> popSeq[i];
    
    int pushIdx = 0, popIdx = 0;
    
    while (pushIdx < n) {
        stk[++tt] = pushSeq[pushIdx++];
        
        while (tt > 0 && stk[tt] == popSeq[popIdx]) {
            tt--;
            popIdx++;
        }
    }
    
    cout << (popIdx == n ? "Yes" : "No") << endl;
    return 0;
}

变式 2:求所有可能的出栈序列

题目

给定 n,入栈顺序为 1, 2, ..., n,求出所有可能的出栈序列。

核心思路

DFS + 回溯,模拟每一步是「入栈」还是「出栈」。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int n;
vector<int> path;  // 出栈序列
stack<int> stk;

void dfs(int pushNum) {
    if (pushNum > n && stk.empty()) {
        for (int x : path) cout << x << " ";
        cout << endl;
        return;
    }
    
    // 选择 1:出栈(如果栈不空)
    if (!stk.empty()) {
        int top = stk.top();
        stk.pop();
        path.push_back(top);
        
        dfs(pushNum);
        
        path.pop_back();
        stk.push(top);
    }
    
    // 选择 2:入栈(如果还有元素可以入栈)
    if (pushNum <= n) {
        stk.push(pushNum);
        dfs(pushNum + 1);
        stk.pop();
    }
}

int main() {
    cin >> n;
    dfs(1);
    return 0;
}

总结

题目 核心思想 代码要点
判断出栈序列是否合法 模拟入栈,匹配就出栈 一个循环入栈,内层 while 出栈
入栈序列不固定 同上,但遍历 pushSeq 两个指针分别跟踪入栈和出栈
求所有可能出栈序列 DFS 回溯 每一步两种选择:入栈或出栈

四、表达式求值

模板题:中缀表达式求值

题目描述

给定一个合法的中缀表达式,包含数字(正整数)、运算符 + - * / 和括号 ( ),计算结果。

样例

复制代码
输入: (1+2)*(3+4)
输出: 21

完整代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

stack<int> num;   // 操作数栈
stack<char> op;   // 运算符栈

// 返回运算符优先级
int priority(char c) {
    if (c == '+' || c == '-') return 1;
    if (c == '*' || c == '/') return 2;
    return 0;
}

// 计算一次
void calc() {
    int b = num.top(); num.pop();
    int a = num.top(); num.pop();
    char c = op.top(); op.pop();
    
    int res;
    if (c == '+') res = a + b;
    else if (c == '-') res = a - b;
    else if (c == '*') res = a * b;
    else res = a / b;
    
    num.push(res);
}

int main() {
    string s;
    cin >> s;
    
    int i = 0;
    while (i < s.length()) {
        if (isdigit(s[i])) {
            // 提取完整的数字
            int x = 0;
            while (i < s.length() && isdigit(s[i])) {
                x = x * 10 + (s[i] - '0');
                i++;
            }
            num.push(x);
            continue;  // 跳过 i++,因为已经在循环里处理了
        }
        
        if (s[i] == '(') {
            op.push('(');
        } else if (s[i] == ')') {
            // 一直计算直到遇到左括号
            while (op.top() != '(') {
                calc();
            }
            op.pop();  // 弹出左括号
        } else {
            // 运算符:先处理栈里优先级不低于当前运算符的
            while (!op.empty() && priority(op.top()) >= priority(s[i])) {
                calc();
            }
            op.push(s[i]);
        }
        i++;
    }
    
    // 处理剩余的运算符
    while (!op.empty()) {
        calc();
    }
    
    cout << num.top() << endl;
    return 0;
}

变式 1:只有加减乘除,没有括号

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

stack<int> num;
stack<char> op;

int priority(char c) {
    if (c == '+' || c == '-') return 1;
    return 2;
}

void calc() {
    int b = num.top(); num.pop();
    int a = num.top(); num.pop();
    char c = op.top(); op.pop();
    
    int res;
    if (c == '+') res = a + b;
    else if (c == '-') res = a - b;
    else if (c == '*') res = a * b;
    else res = a / b;
    
    num.push(res);
}

int main() {
    string s;
    cin >> s;
    
    int i = 0;
    while (i < s.length()) {
        if (isdigit(s[i])) {
            int x = 0;
            while (i < s.length() && isdigit(s[i])) {
                x = x * 10 + (s[i] - '0');
                i++;
            }
            num.push(x);
            continue;
        }
        
        while (!op.empty() && priority(op.top()) >= priority(s[i])) {
            calc();
        }
        op.push(s[i]);
        i++;
    }
    
    while (!op.empty()) calc();
    
    cout << num.top() << endl;
    return 0;
}

变式 2:中缀转后缀(逆波兰表达式)

题目

将中缀表达式转换为后缀表达式(不需要计算结果)。

核心思路

和中缀求值几乎一样,只是遇到数字直接输出,遇到运算符时输出栈里优先级不低于它的运算符。

样例

复制代码
输入: (1+2)*(3+4)
输出: 12+34+*

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int priority(char c) {
    if (c == '+' || c == '-') return 1;
    if (c == '*' || c == '/') return 2;
    return 0;
}

int main() {
    string s;
    cin >> s;
    
    stack<char> op;
    string result;
    
    for (char c : s) {
        if (isdigit(c)) {
            result += c;
        } else if (c == '(') {
            op.push(c);
        } else if (c == ')') {
            while (op.top() != '(') {
                result += op.top();
                op.pop();
            }
            op.pop();
        } else {
            while (!op.empty() && priority(op.top()) >= priority(c)) {
                result += op.top();
                op.pop();
            }
            op.push(c);
        }
    }
    
    while (!op.empty()) {
        result += op.top();
        op.pop();
    }
    
    cout << result << endl;
    return 0;
}

变式 3:后缀表达式求值

题目

给定一个后缀表达式(逆波兰表达式),计算结果。

核心思路

遇到数字入栈,遇到运算符弹出两个数字计算,结果入栈。

样例

复制代码
输入: 1 2 + 3 4 + *
输出: 21

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int main() {
    string s;
    getline(cin, s);
    
    stack<int> stk;
    int i = 0;
    
    while (i < s.length()) {
        if (s[i] == ' ') {
            i++;
            continue;
        }
        
        if (isdigit(s[i])) {
            int x = 0;
            while (i < s.length() && isdigit(s[i])) {
                x = x * 10 + (s[i] - '0');
                i++;
            }
            stk.push(x);
        } else {
            int b = stk.top(); stk.pop();
            int a = stk.top(); stk.pop();
            
            int res;
            if (s[i] == '+') res = a + b;
            else if (s[i] == '-') res = a - b;
            else if (s[i] == '*') res = a * b;
            else res = a / b;
            
            stk.push(res);
            i++;
        }
    }
    
    cout << stk.top() << endl;
    return 0;
}

变式 4:CSP 真题 - 二十四点

题目描述

给定四个数字和三个运算符(只能是 + - x /),判断能否计算出 24。

注意:这里的除法是整数除法,且不考虑括号,按顺序计算。

样例

复制代码
输入: 1 2 3 4 + - x /
输出: Yes (1+2+3)*4 = 24

核心思路

因为只有四个数字和三个运算符,可以直接枚举所有可能的运算顺序(全排列 + 运算符组合),也可以用栈模拟。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int calc(int a, int b, char op) {
    if (op == '+') return a + b;
    if (op == '-') return a - b;
    if (op == 'x') return a * b;
    return a / b;
}

int main() {
    int n;
    cin >> n;
    
    while (n--) {
        string s;
        cin >> s;
        
        stack<int> num;
        stack<char> op;
        
        for (char c : s) {
            if (isdigit(c)) {
                num.push(c - '0');
            } else {
                // 遇到运算符,先处理栈里同级的运算符
                while (!op.empty()) {
                    int b = num.top(); num.pop();
                    int a = num.top(); num.pop();
                    num.push(calc(a, b, op.top()));
                    op.pop();
                }
                op.push(c);
            }
        }
        
        while (!op.empty()) {
            int b = num.top(); num.pop();
            int a = num.top(); num.pop();
            num.push(calc(a, b, op.top()));
            op.pop();
        }
        
        if (num.top() == 24) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
    return 0;
}

五、DFS 栈模拟

1. 核心思想

递归的本质就是栈。系统在执行递归函数时,会把每一次函数调用的状态(参数、局部变量、返回地址)压入系统栈。当函数返回时,再从栈中恢复。

栈模拟递归 就是用显式的栈来模拟这个过程,避免系统栈溢出(递归深度太大时会发生)。

模板套路

  1. 定义一个栈,存储当前的状态(节点、参数等)

  2. 用一个循环模拟递归的执行流程

  3. 遇到需要递归的地方,就把当前状态入栈,然后处理子问题

  4. 子问题处理完后,从栈中恢复父问题的状态继续执行

2. 什么时候需要用栈模拟递归

场景 原因
递归深度过大(超过 10^5) 系统栈会溢出
题目明确要求非递归实现 考察对递归本质的理解
需要自定义遍历顺序 栈可以灵活控制
某些竞赛环境递归栈空间有限 防止爆栈

二叉树中序遍历的栈实现

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

vector<int> inorderTraversal(TreeNode* root) {
    vector<int> result;
    stack<TreeNode*> stk;
    TreeNode* cur = root;
    
    while (cur != NULL || !stk.empty()) {
        // 一直往左走,沿途入栈
        while (cur != NULL) {
            stk.push(cur);
            cur = cur->left;
        }
        
        // 弹出栈顶,访问
        cur = stk.top();
        stk.pop();
        result.push_back(cur->val);
        
        // 转向右子树
        cur = cur->right;
    }
    
    return result;
}

二叉树前序遍历的栈实现

cpp 复制代码
vector<int> preorderTraversal(TreeNode* root) {
    vector<int> result;
    if (root == NULL) return result;
    
    stack<TreeNode*> stk;
    stk.push(root);
    
    while (!stk.empty()) {
        TreeNode* node = stk.top();
        stk.pop();
        result.push_back(node->val);
        
        // 先右后左,因为栈是后进先出
        if (node->right) stk.push(node->right);
        if (node->left) stk.push(node->left);
    }
    
    return result;
}

二叉树后序遍历的栈实现

cpp 复制代码
vector<int> postorderTraversal(TreeNode* root) {
    vector<int> result;
    if (root == NULL) return result;
    
    stack<TreeNode*> stk1, stk2;
    stk1.push(root);
    
    while (!stk1.empty()) {
        TreeNode* node = stk1.top();
        stk1.pop();
        stk2.push(node);
        
        if (node->left) stk1.push(node->left);
        if (node->right) stk1.push(node->right);
    }
    
    while (!stk2.empty()) {
        result.push_back(stk2.top()->val);
        stk2.pop();
    }
    
    return result;
}
相关推荐
LJHclasstore_luo18 小时前
【C++题解】112354.平行时空
数据结构·c++·算法
小陈phd20 小时前
QAnything 阅读优化策略03——查询转换
算法
良木生香20 小时前
【C++初阶】STL—— Stack & Queue 从入门到精通:容器适配器、迭代器与经典面试题
java·开发语言·c++·算法·zookeeper
小小晓.20 小时前
C++小白记:vector
开发语言·c++·算法
雪的季节20 小时前
Python 垃圾回收触发完整机制
java·jvm·算法
tkevinjd20 小时前
力扣72-编辑距离
算法·leetcode·职场和发展
小刘学技术20 小时前
AI人工智能决策树分类器:原理、实现与应用
开发语言·人工智能·python·算法·决策树·机器学习·数据挖掘
网络与设备以及操作系统学习使用者20 小时前
生成树防环,Super-VLAN省IP,端口安全护网络
运维·网络·学习·深度优先
caimouse21 小时前
mm学习笔记_04:VAD树算法与地址空间分配
笔记·学习·算法·reactos