《王道论坛计算机考研机试指南》第四章【数据结构】代码

一、栈的应用

括号匹配问题

#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
stack<int> S;
char str[110];   // 保存输入字符串
char ans[110];   // 保存输出字符串
int main() {
    while (scanf("%s", str) != EOF) {
        int i;
        for (i = 0; str[i] != '\0'; i++) { // 从左到右遍历字符串
            if (str[i] == '(') {   // 若遇到左括号
                S.push(i);     // 将其数组下标放入栈中
                ans[i] = ' ';    // 暂且将对应的输出字符串位置改为空格
            }
            else if (str[i] == ')') {   // 若遇到右括号
                if (!S.empty()) {   // 若此时栈非空
                    S.pop();
                    ans[i] = ' ';   // 正确匹配,修改输出中该位置为空格
                }
                else ans[i] = '?';     // 若栈为空,则无法找到左括号与其匹配,修改输出中该位置为?
            }
            else ans[i] = ' ';   // 若为其它字符,与括号匹配无关,则修改输出为空格
        }
        while (!S.empty()) {   // 当字符串遍历完成后,尚留在栈中的左括号无法匹配
            ans[S.top()] = '$';    // 修改骑在输出中的位置为$
            S.pop();    // 弹出
        }
        ans[i] = '\0';     // 为了使输出形成字符串,在最后一个字符后添加一个空字符
        printf("%s\n", str);
        printf("%s\n", ans);    // 输出原字符串和答案字符串
    }
    return 0;
}

当右括号出现时,和栈中左括号匹配时,要注意判断栈是否为空,不能直接s.top()
在牛客上打一个很简单的括号匹配问题时,我就是犯了这个错误,导致出现了段错误。

利用堆栈对表达式求值

#include <stack>
#include <iostream>
using namespace std;
char str[220];    // 保存表达式字符串
/*
 优先级矩阵,若mat[i][j] == 1,则表示i号运算度优先级大于j号运算符
 运算符编码规则为+为1号,-为2号,*为3号,/为4号,我们人为添加在表达式首尾的标记运算符为0号
 */
int mat[][5] = {1, 0, 0, 0, 0,
                1, 0, 0, 0, 0,
                1, 0, 0, 0, 0,
                1, 1, 1, 0, 0,
                1, 1, 1, 0, 0 };
stack<int> op;    // 运算符栈,保存着运算符编号
stack<double> in;    // 数字栈,运算结果可能存在浮点数,所以保存元素为double
/* 获得表达式中下一个元素函数,若函数运行结束时,引用变量reto为true,则表示该元素为一个运算符,其编号保存在引用变量retn中;
 否则,表示该元素为一个数字,其值保存在引用变量retn中,引用变量i表示便利到的字符串下标
 */
void getOp(bool &reto, int & retn, int &i) {
    if (i == 0 && op.empty() == true) {  // 若此时遍历字符串第一个字符,且运算符栈为空,我们人为添加编号为0的标记字符
        reto = true;    // 为运算符
        retn = 0;     // 编号为0
        return;   // 返回
    }
    if (str[i] == '\0') {  // 若此时遍历字符为空字符,则表示字符串已经被遍历完
        reto = true;       // 返回为运算符
        retn = 0;          // 编号为0的标记字符
        return;
    }
    if (str[i] >= '0' && str[i] <= '9') {   // 若当前字符为数字
        reto = false;

    } else {  // 否则
        reto = true;
        if (str[i] == '+') {
            retn = 1;
        } else if (str[i] == '-') {
            retn = 2;
        } else if (str[i] == '*') {
            retn = 3;
        } else if (str[i] == '/') {
            retn = 4;
        }
        i += 2;   // i递增,跳过该运算字符和该运算字符后的空格
        return;
    }
    retn = 0;    // 返回结果为数字
    // 若字符串未被遍历完,且下一个字符不是空格,则依次遍历其后数字,计算当前连续数字字符表示的数值
    for (; str[i] != ' ' && str[i] != '\0'; i++) {
        retn *= 10;
        retn += str[i]-'0';
    }
    if (str[i] == ' ')  // 若其后字符为空格,则表示字符串未被遍历完
        i++;   // 递增,跳过该空格
    return;
}
int main() {
    while (gets(str) ) {  // 输入字符串,当其位于文件尾时,gets返回0
        if (str[0] == '0' && str[1] == '\0') break;    // 若输入只有一个0,则退出
        bool retop;
        int retnum;    // 定义函数所需的引用变量
        int idx = 0;   // 定义遍历到的字符串下标,初始值为0
        while (!op.empty())
            op.pop();
        while (!in.empty())
            in.pop();   // 清空数字栈和运算符栈
        while (true) {   // 循环遍历表达式字符串
            getOp(retop, retnum, idx);    // 获取表达式中下一个元素
            if (retop == false) {   // 若该元素为数字
                in.push((double)retnum);    // 将其压人数字栈中
            } else {
                double tmp;
                if (op.empty() || mat[retnum][op.top()] == 1) {
                    op.push(retnum);
                }  // 若运算符栈为空或者当前便利到的运算符优先级大于站定运算符,则将该运算符压入运算符栈
                else {
                    while (mat[retnum][op.top()] == 0) {  // 只要当前运算符优先级小于栈顶元素运算符,则重复循环
                        int ret = op.top();  // 保存栈顶运算符
                        op.pop();
                        double b = in.top();
                        in.pop();
                        double a = in.top();
                        in.pop();
                        if(ret == 1) tmp = a + b;
                        else if (ret == 2) tmp = a - b;
                        else if (ret == 3) tmp = a * b;
                        else tmp = a / b;
                        in.push(tmp);   // 将结果压回数字栈
                    }
                    op.push(retnum);   // 将当前运算符压入运算符栈
                }
            }
            if (op.size() == 2 && op.top() == 0) break;   // 若运算符栈中只有两个元素,且其栈顶元素为标记运算符明则表示表达式求值结束
        }
        printf("%.2f\n", in.top());    // 输出数字栈中位移的数字,即为答案
    }
    return 0;
}

这道题要注意,对栈中两个数字进行表达式求值时,在栈中下面位置的是左操作数,在上面的是右操作数。

猜你喜欢

转载自blog.csdn.net/beashaper_/article/details/80719058