本文介绍了栈的三种算法,分别是括号匹配算法,中缀表达式转后缀表达式算法和后缀表达式计算算法。同时,还写了一个计算器的例子将这三种算法结合起来。
括号匹配算法
- 初始化一个空栈,顺序读入括号
- 若是右括号则与栈顶元素进行匹配(若匹配,则弹出栈顶元素并进行下一元素;若不匹配,则该序列不合法)
- 若是左括号,则压入栈中
- 若全部元素遍历完毕,栈中仍然存在元素,则该序列不合法
中缀表达式转后缀表达式算法
- 从左到右遍历中缀表达式的每个数字和符号
- 如果检测到数字,则直接加入到后缀表达式中
- 如果检测到运算符时:
- 若为
(
,入栈
- 若为
)
,则依次将栈中的运算符加入后缀表达式,直到出现 (
,并从栈中删除 (
- 若为
+
,-
,*
,/
, 则一直将栈顶元素加入到后缀表达式中,并弹出。直到栈顶元素的优先级低于自身或遇到 (
。
- 一直到最终输出后缀表达式为止。
后缀表达式计算算法
- 建立一个操作数栈 S。
- 从左到右读表达式,如果读到操作数就将它压入栈 S 中,如果读到运算符,则取出由栈顶向下的 2 项操作数进行运算,再将运算的结果代替原栈顶的 2 项压入栈中
计算器例子
该计算器使用 c++
语言编写,版本要大于 11 即可编译。可以实现 0-9 以内的加减乘除。支持括号。可以判断符号优先级。
由于只是为了练习一下栈的算法,所以没有过多的错误处理和更加优秀的程序结构。
大体思路:
- 读入一个要计算的表达式
- 判断括号是否匹配,如果不匹配则返回(括号匹配算法)
- 将中缀表达式转换为后缀表达式(中缀表达式转后缀表达式算法)
- 计算后缀表达式的值(后缀表达式计算算法)
- 输出后缀表达式的值,跳转到步骤 1
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
| #include <iostream> #include <algorithm> #include <cstring> #include <stack> using namespace std;
int level(char t) { if (t >= '0' && t <= '9') { return 0; } else if (t == '+' || t == '-') { return 1; } else if (t == '*' || t == '/') { return 2; } else if (t == '(') { return 3; } return 4; }
bool check(string &str) { stack<char> s; for (auto &i : str) { if (i == '(') { s.push(i); } else if (i == ')') { if (s.empty()) { return false; } s.pop(); } } if (!s.empty()) { return false; } return true; }
string convert(string &str) { string ans; stack<char> s; for (auto &i : str) { switch (level(i)) { case 0: { ans.push_back(i); break; } case 1: { while (!s.empty() && level(s.top()) >= 1 && level(s.top()) != 3) { ans.push_back(s.top()); s.pop(); } s.push(i); break; } case 2: { while (!s.empty() && level(s.top()) >= 2 && level(s.top()) != 3) { ans.push_back(s.top()); s.pop(); } s.push(i); break; } case 3: { s.push(i); break; } case 4: { while (!s.empty() && level(s.top()) != 3) { ans.push_back(s.top()); s.pop(); } s.pop(); break; } } } while (!s.empty()) { ans.push_back(s.top()); s.pop(); } return ans; }
double compute(string &str) { string con = convert(str); stack<char> sc; stack<double> si; for (auto &i : con) { if (level(i) == 0) { si.push(i - '0'); } else { double b = si.top(); si.pop(); double a = si.top(); si.pop(); double ans; if (i == '+') ans = a + b; else if (i == '-') ans = a - b; else if (i == '*') ans = a * b; else ans = a / b; si.push(ans); } } return si.top(); } int main() { while (1) { string str; cin >> str; if (!check(str)) { cout << "当前的括号不匹配" << endl; continue; } cout << compute(str) << endl; } return 0; }
|