前缀表达式和后缀表达式 - C++代码
目录
- 速览
- 前缀表达式
- 前缀表达式的运算规则
- 中缀表达式转换为前缀表达式
- 后缀表达式
- 后缀表达式的运算
- 中缀表达式转换为后缀表达式
刷题向文章,不介绍原理,只介绍规则
速览
算术表达式分为:
- 前缀表达式(波兰式)
- 后缀表达式(逆波兰式)
- 中缀表达式
中缀表达式是我们最熟悉的表达式,是常见的运算式,如下所示:
(2 + 3) * 4 - 5
这就是一个中缀表达式
相对于中缀表达式,前缀表达式的运算符在操作数之前,把上面的中缀表达式改写成前缀表达式为:
- * + 2 3 4 5
注意,并不是所有运算符在所有数字之前,如:
+ - 1 2 * 3 5
也可以是前缀表达式
前缀表达式
前缀表达式的运算规则
从右向左依次扫描表达式,如果扫描到数字,则把数字压入栈
如果扫描到运算符,则依次弹出栈顶的两个数字进行计算,并把计算结果压入栈
例:计算前缀表达式 - * +2345 的值
扫描值 | 堆栈 | 计算值 |
---|---|---|
5 | 5 | |
4 | 5 4 | |
3 | 5 4 3 | |
2 | 5 4 3 2 | |
+ | 5 4 5 | 2+3=5 |
* | 5 20 | 5*4=20 |
- | 15 | 20-5=15 |
前缀表达式的值为 15
中缀表达式转换为前缀表达式
创建2个空栈 S1 和 S2,S1 为符号栈,S2 为临时栈,从右向左扫描中缀表达式
- 如果遇到数字,压入 S2 栈中
- 如果遇到符号:
如果 S1 为空栈,或者 S1 栈顶为右括号,直接压入 S1 中
如果扫描到的符号优先级大于等于 S1 栈顶的符号,直接压入 S1 中
如果扫描到的符号优先级小于 S1 栈顶的符号,则把 S1 栈顶的符号弹出并压入 S2,重复这一步骤,直到可以把扫描到的符号压入 S1 - 如果遇到括号:
如果遇到左括号,直接压入 S1
如果遇到右括号,依次弹出 S1 栈顶的符号并压入 S2,直到遇到左括号时,丢弃这一对括号
最后,依次把 S1 栈顶元素弹出压入 S2 中,依次弹出 S2 栈顶元素,得到前缀表达式
例:把中缀表达式 1+((2+3) * 4)-5 转换为前缀表达式
扫描值 | 操作 | S1 | S2 |
---|---|---|---|
5 | 压入S2 | 5 | |
- | 压入S1 | - | 5 |
) | 压入S1 | -) | 5 |
4 | 压入S2 | -) | 5 4 |
* | 压入S1 | -)* | 5 4 |
) | 压入S1 | -)*) | 5 4 |
3 | 压入S2 | -)*) | 5 4 3 |
+ | 压入S1 | -)*)+ | 5 4 3 |
2 | 压入S2 | -)*)+ | 5 4 3 2 |
( | 弹出+,压入S2 | -)* | 5 4 3 2+ |
( | 弹出*,压入S2 | - | 5 4 3 2+* |
+ | 压入S1 | -+ | 5 4 3 2+* |
1 | 压入S2 | -+ | 5 4 3 2+*1 |
NULL | 依次弹出S1栈顶压入S2 | 5 4 3 2+*1+ - |
所求前缀表达式为:-+1*+2345
代码实现:
// 前缀表达式练习 - 只能输入 0-9 的数
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;bool isoperator(int _C);
bool isbrackets(int _C);int main(int argc, char*argv[]) {// 输入中缀表达式string infix;cin >> infix;// 中缀表达式 => 前缀表达式stack<char>S1, S2;for (auto it = infix.crbegin(); it != infix.crend(); it++) {if (isdigit(*it))S2.push(*it);else if (isoperator(*it)) {CASE_ISOPERATOR:if (S1.empty() || ')' == S1.top())S1.push(*it);else if ('+' == S1.top() || '-' == S1.top())S1.push(*it);else if ('*' == *it || '/' == *it)S1.push(*it);else {S2.push(S1.top());S1.pop();goto CASE_ISOPERATOR;}}else if (isbrackets(*it)) {if (')' == *it)S1.push(*it);else {while (!isbrackets(S1.top())) {S2.push(S1.top());S1.pop();}S1.pop();}}}while (!S1.empty()) {S2.push(S1.top());S1.pop();}string prefix;while (!S2.empty()) {prefix.push_back(S2.top());S2.pop();}// 计算前缀表达式的值stack<int>value;for (auto it = prefix.crbegin(); it != prefix.crend(); it++) {if (isdigit(*it))value.push(*it - '0');else {int top, second_top;top = value.top();value.pop();second_top = value.top();value.pop();switch (*it) {case'+':value.push(top + second_top); break;case'-':value.push(top - second_top); break;case'*':value.push(top*second_top); break;case'/':value.push(top / second_top); break;}}}// 输出前缀表达式及其值cout << prefix << '=' << value.top() << endl;return 0;
}bool isoperator(int _C) {return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}bool isbrackets(int _C) {return '(' == _C || ')' == _C ? true : false;
}
后缀表达式
后缀表达式的运算
从左向右依次扫描表达式,如果扫描到数字,则把数字压入栈
如果扫描到运算符,则弹出栈顶的两个数字进行计算,并把计算结果压入栈
(和前缀表达式不同,结果 = 次顶数字 operator 顶部数字)
例:计算后缀表达式 23+4 * 5- 的值
扫描值 | 堆栈 | 计算值 |
---|---|---|
2 | 2 | |
3 | 2 3 | |
+ | 5 | 2+3=5 |
4 | 5 4 | |
* | 20 | 5*4=20 |
5 | 20 | 5 |
- | 15 | 20-5=15 |
后缀表达式的值为 15
中缀表达式转换为后缀表达式
创建2个空栈 S1 和 S2,S1 为符号栈,S2 为临时栈,从左向右扫描中缀表达式
- 如果遇到数字,压入 S2 栈中
- 如果遇到符号:
如果 S1 为空栈,或者 S1 栈顶为左括号,直接压入 S1 中
如果扫描到的符号优先级大于 S1 栈顶的符号,直接压入 S1 中
(注意前缀表达式是大于等于,而后缀表达式只有大于才可以直接压入)
如果扫描到的符号优先级小于 S1 栈顶的符号,则把 S1 栈顶的符号弹出并压入 S2,重复这一步骤,直到可以把扫描到的符号压入 S1 - 如果遇到括号:
如果遇到右括号,直接压入 S1
如果遇到左括号,依次弹出S1栈顶的符号并压入 S2,直到遇到左括号时,丢弃这一对括号
最后,依次把 S1 栈顶元素弹出压入 S2 中,依次弹出 S2 栈顶元素,“反向输出”,得到前缀表达式
例:把中缀表达式 1+((2+3) * 4)-5 转换为前缀表达式
扫描值 | 操作 | S1 | S2 |
---|---|---|---|
1 | 压入S2 | NULL | 1 |
+ | 压入S1 | + | 1 |
( | 压入S1 | +( | 1 |
( | 压入S1 | +(( | 1 |
2 | 压入S2 | +(( | 1 2 |
+ | 压入S1 | +((+ | 1 2 |
3 | 压入S2 | +((+ | 1 2 3 |
) | 弹出+,压入S2 | +( | 1 2 3+ |
* | 压入S1 | +(* | 1 2 3+ |
4 | 压入S2 | +(* | 1 2 3+4 |
) | 弹出*,压入S2 | + | 1 2 3+4* |
- | 弹出+压入S1,压入S1 | - | 1 2 3+4*+ |
5 | 压入S2 | - | 1 2 3+4*+5 |
NULL | 依次弹出S1顶部元素,压入S2 | 1 2 3+4*+5- |
所求后缀表达式为:1 2 3+4*+5-
代码实现:
// 后缀表达式练习 - 只能输入 0-9 的数
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;bool isoperator(int _C);
bool isbrackets(int _C);int main(int argc, char*argv[]) {// 输入中缀表达式string infix;cin >> infix;// 中缀表达式 => 后缀表达式stack<char>S1, S2;for (auto it = infix.cbegin(); it != infix.cend(); it++) {if (isdigit(*it))S2.push(*it);else if (isoperator(*it)) {CASE_ISOPERATOR:if (S1.empty() || '(' == S1.top())S1.push(*it);else if (('+' == S1.top() || '-' == S1.top()) && ('*' == *it || '/' == *it))S1.push(*it);else {S2.push(S1.top());S1.pop();goto CASE_ISOPERATOR;}}else if (isbrackets(*it)) {if ('(' == *it)S1.push(*it);else {while (!isbrackets(S1.top())) {S2.push(S1.top());S1.pop();}S1.pop();}}}while (!S1.empty()) {S2.push(S1.top());S1.pop();}string prefix;while (!S2.empty()) {prefix.insert(prefix.begin(), S2.top());S2.pop();}// 计算后缀表达式的值stack<int>value;for (auto it = prefix.cbegin(); it != prefix.cend(); it++) {if (isdigit(*it))value.push(*it - '0');else {int top, second_top;top = value.top();value.pop();second_top = value.top();value.pop();switch (*it) {case'+':value.push(second_top + top); break;case'-':value.push(second_top - top); break;case'*':value.push(second_top*top); break;case'/':value.push(second_top / top); break;}}}// 输出后缀表达式及其值cout << prefix << '=' << value.top() << endl;return 0;
}bool isoperator(int _C) {return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}bool isbrackets(int _C) {return '(' == _C || ')' == _C ? true : false;
}
优化代码:
// 后缀表达式求值
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;bool isop(char _C);
void orgnize(string&str);int main() {string input, buffer;while (!cin.eof()) {cin >> buffer;input.append(buffer);input.push_back(32);buffer.clear();}orgnize(input);stack<int>value;for (auto it = input.begin(); it != input.end();) {if (isdigit(*it)) {while (isdigit(*it))buffer.push_back(*it++);value.push(atoi(buffer.c_str()));buffer.clear();}else if (isop(*it)) {int top, second_top;top = value.top();value.pop();second_top = value.top();value.pop();switch (*it++) {case'+':value.push(second_top + top); break;case'-':value.push(second_top - top); break;case'*':value.push(second_top * top); break;case'/':value.push(second_top / top); break;}}else it++;}cout << "postfix(" << input << ")=" << value.top() << endl;return 0;
}bool isop(char _C) {return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}void orgnize(string&str) {while (!str.empty())if (isspace(*str.rbegin()))str.pop_back();else break;while (!str.empty())if (isspace(*str.begin()))str.erase(str.begin());else break;for (auto it = str.begin(); it != str.end();)if (isspace(*it++))while (isspace(*it))it = str.erase(it);for (auto it = str.begin(); it != str.end() - 1; it++) {if (isdigit(*it) && isop(it[1]))it = str.insert(it + 1, 32);else if (isop(*it) && (isdigit(it[1]) || isop(it[1])))it = str.insert(it + 1, 32);}
}
// 中缀 - 后缀转换
// infix to postfix
#include<iostream>
using std::cin;
using std::cout;
using std::ostream;
using std::endl;
#include<string>
using std::string;
#include<stack>
using std::stack;
#include<vector>
using std::vector;struct CharInt {bool ischar;int charint;CharInt(bool isch, int chint) :ischar(isch), charint(chint) {}
};
ostream&operator<<(ostream&output, CharInt x) {if (x.ischar)output << static_cast<char>(x.charint);else output << x.charint;return output;
}bool isop(char _C) {return '+' == _C || '-' == _C || '*' == _C || '/' == _C ? true : false;
}int main() {char buffer[128];cin.getline(buffer, sizeof(buffer));stack<char>S1;stack<CharInt>S2;for (auto it = buffer; *it;) {if (isdigit(*it)) {string temp;while (isdigit(*it))temp.push_back(*it++);S2.push(CharInt(false, atoi(temp.c_str())));}else if (isop(*it)) {CASE_ISOP:if (S1.empty() || '(' == S1.top())S1.push(*it);else if (('+' == S1.top() || '-' == S1.top()) && ('*' == *it || '/' == *it))S1.push(*it);else {S2.push(CharInt(true, S1.top()));S1.pop();goto CASE_ISOP;}it++;}else if ('(' == *it)S1.push(*it++);else if (')' == *it++) {while (S1.top() != '(') {S2.push(CharInt(true, S1.top()));S1.pop();}S1.pop();}}while (!S1.empty()) {S2.push(CharInt(true, S1.top()));S1.pop();}vector<CharInt>output;while (!S2.empty()) {output.insert(output.begin(), S2.top());S2.pop();}for (auto it : output)cout << it << ' ';cout.put(10);return 0;
}
前缀表达式和后缀表达式 - C++代码相关推荐
- 前缀、中缀和后缀表达式详解,中缀表达式到后缀表达式的转换规则,以及后缀表达式的计算规则,附计算代码
1. 中缀.前缀和后缀表达式 1.1 中缀表达式 首先,中缀表达式的这个"缀"指运算符在两个操作数的位置.中缀表达式其实就是我们常用的算术表达式,比如 2 + 9 - (32 * ...
- 数据结构 - 栈 (逆波兰计算器)(栈的三种表达式)(前缀、中缀和后缀表达式,后缀也叫逆波兰表达式)(中缀表达式转后缀表达式实现步骤及完整代码)
栈的三种表达式:前缀.中缀和后缀表达式,后缀也叫逆波兰表达式 前缀(波兰表达式) 中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式) 后缀(逆波兰表达式) 计算过程 ...
- 中缀表达式到前缀表达式和后缀表达式
1.算法思路 转化为后缀:从左到右遍历中缀表达式,遇到操作数,输出,遇到操作符,当前操作符的优先级大于栈顶操作符优先级,进栈,否则,弹出栈顶优先级大于等于当前操作符的操作符,当前操作符进栈. ...
- 前缀表达式与后缀表达式求法(栈的应用)
1.前缀.中缀.后缀表达式 中缀表达式即为人们熟悉的数学运算式子写法.而前缀.后缀表达式是为了计算机计算方便的写法. 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操 ...
- 【数据结构与算法】【12】前缀表达式、中缀表达式、后缀表达式
什么是前缀表达式.中缀表达式.后缀表达式 前缀表达式.中缀表达式.后缀表达式,是通过树来存储和计算表达式的三种不同方式 以如下公式为例 (a+(b−c))∗d( a+(b-c) )*d(a+(b−c) ...
- 数据结构 - 拓展突破(C++实现中缀表达式转前缀表达式,中缀表达式转后缀表达式,前缀表达式求值,中缀表达式求值)
文章目录 1. C++中缀表达式转后缀表达式 2. C++中缀表达式转前缀表达式 3. C++后缀表达式求值 4. C++前缀表达式求值 1. C++中缀表达式转后缀表达式 输入中缀表达式样例: 2+ ...
- 中缀表达式转换成前缀表达式和后缀表达式的极其简单方法
35,15,+,80,70,-,*,20,/ //后缀表达方式 (((35+15)*(80-70))/20)=25 //中缀表达方式 /,*,+,35,15,-,80,70, 20 //前缀表达方式 ...
- 中缀表达式转后缀表达式详细思路及代码实现
什么是中缀表达式? 中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(eg:3+4.3+4*2.8+(17-6*2)-.). 为什么要中缀表达式转后缀表达式? 但是中 ...
- 前缀表达式、中缀表达式、后缀表达式的区别
一.三者的概念(参考维基百科) 1.1中缀表达式 中缀表达式是符合人类直觉的一种表达方式,其特点是操作符(二元操作符)在中间,操作数在两侧. 例如 3 + 4 , 5 - 6 * 7, ( ...
最新文章
- 2021年大数据Kafka(五):❤️Kafka的java API编写❤️
- bind98-内网智能DNS之master服务器构建
- idea 文件流读取web-inf下的文件_C#初学者教程系列20:Stream流读写
- Perforce 使用说明
- 阿里巴巴开源OpenJDK长期支持版本,Java全球管理组织唯一中国企业
- linux 编译java并打包
- 平均成绩计算机控件,计算机技术基础(第十二章 文件 )
- ubuntu 13.04 mysql_Ubuntu13.04 下MySQL5.6安装过程
- windows下使用Nginx服务器实现负载均衡方法
- 微课|中学生可以这样学Python(1.2节):IDLE环境使用简介
- View 绘制体系知识梳理(4) 绘制过程之 Layout 详解
- 双层板在哪层覆铜_2020年中国印制电路板行业发展现状及发展趋势预测(图)...
- 《Puppet权威指南》——第1章 运维工程师的利器——自动化运维工具
- 词根词缀学单词/优秀词典推荐
- 欲说还休,欲说还休,却道天凉好个秋
- 有个人在偷偷的爱着你
- e路航 LH900N地图升级
- php网站banner图片切换,最简单的Banner轮播左右切换效果代码及实现思路(附带源码)...
- android添加nfc门禁卡,IOS14nfc怎么添加门禁卡?NFC门禁卡教程[多图]
- css3-属性选择器 伪类:root :not() :first-of-type :first-child 伪元素 ::first-letter ::first-line ::selection等等