目录

  • 速览
  • 前缀表达式
    • 前缀表达式的运算规则
    • 中缀表达式转换为前缀表达式
  • 后缀表达式
    • 后缀表达式的运算
    • 中缀表达式转换为后缀表达式

刷题向文章,不介绍原理,只介绍规则

速览

算术表达式分为:

  • 前缀表达式(波兰式)
  • 后缀表达式(逆波兰式)
  • 中缀表达式

中缀表达式是我们最熟悉的表达式,是常见的运算式,如下所示:

(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 为临时栈,从右向左扫描中缀表达式

  1. 如果遇到数字,压入 S2 栈中
  2. 如果遇到符号:
    如果 S1 为空栈,或者 S1 栈顶为右括号,直接压入 S1 中
    如果扫描到的符号优先级大于等于 S1 栈顶的符号,直接压入 S1 中
    如果扫描到的符号优先级小于 S1 栈顶的符号,则把 S1 栈顶的符号弹出并压入 S2,重复这一步骤,直到可以把扫描到的符号压入 S1
  3. 如果遇到括号:
    如果遇到左括号,直接压入 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 为临时栈,从左向右扫描中缀表达式

  1. 如果遇到数字,压入 S2 栈中
  2. 如果遇到符号:
    如果 S1 为空栈,或者 S1 栈顶为左括号,直接压入 S1 中
    如果扫描到的符号优先级大于 S1 栈顶的符号,直接压入 S1 中
    (注意前缀表达式是大于等于,而后缀表达式只有大于才可以直接压入)
    如果扫描到的符号优先级小于 S1 栈顶的符号,则把 S1 栈顶的符号弹出并压入 S2,重复这一步骤,直到可以把扫描到的符号压入 S1
  3. 如果遇到括号:
    如果遇到右括号,直接压入 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.1 中缀表达式 首先,中缀表达式的这个"缀"指运算符在两个操作数的位置.中缀表达式其实就是我们常用的算术表达式,比如 2 + 9 - (32 * ...

  2. 数据结构 - 栈 (逆波兰计算器)(栈的三种表达式)(前缀、中缀和后缀表达式,后缀也叫逆波兰表达式)(中缀表达式转后缀表达式实现步骤及完整代码)

    栈的三种表达式:前缀.中缀和后缀表达式,后缀也叫逆波兰表达式 前缀(波兰表达式) 中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式) 后缀(逆波兰表达式) 计算过程 ...

  3. 中缀表达式到前缀表达式和后缀表达式

    1.算法思路 转化为后缀:从左到右遍历中缀表达式,遇到操作数,输出,遇到操作符,当前操作符的优先级大于栈顶操作符优先级,进栈,否则,弹出栈顶优先级大于等于当前操作符的操作符,当前操作符进栈.     ...

  4. 前缀表达式与后缀表达式求法(栈的应用)

    1.前缀.中缀.后缀表达式 中缀表达式即为人们熟悉的数学运算式子写法.而前缀.后缀表达式是为了计算机计算方便的写法. 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操 ...

  5. 【数据结构与算法】【12】前缀表达式、中缀表达式、后缀表达式

    什么是前缀表达式.中缀表达式.后缀表达式 前缀表达式.中缀表达式.后缀表达式,是通过树来存储和计算表达式的三种不同方式 以如下公式为例 (a+(b−c))∗d( a+(b-c) )*d(a+(b−c) ...

  6. 数据结构 - 拓展突破(C++实现中缀表达式转前缀表达式,中缀表达式转后缀表达式,前缀表达式求值,中缀表达式求值)

    文章目录 1. C++中缀表达式转后缀表达式 2. C++中缀表达式转前缀表达式 3. C++后缀表达式求值 4. C++前缀表达式求值 1. C++中缀表达式转后缀表达式 输入中缀表达式样例: 2+ ...

  7. 中缀表达式转换成前缀表达式和后缀表达式的极其简单方法

    35,15,+,80,70,-,*,20,/ //后缀表达方式 (((35+15)*(80-70))/20)=25 //中缀表达方式 /,*,+,35,15,-,80,70, 20 //前缀表达方式 ...

  8. 中缀表达式转后缀表达式详细思路及代码实现

    什么是中缀表达式? 中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(eg:3+4.3+4*2.8+(17-6*2)-.). 为什么要中缀表达式转后缀表达式? 但是中 ...

  9. 前缀表达式、中缀表达式、后缀表达式的区别

    一.三者的概念(参考维基百科) 1.1中缀表达式 中缀表达式是符合人类直觉的一种表达方式,其特点是操作符(二元操作符)在中间,操作数在两侧. 例如 3 + 4 ,   5 - 6 * 7,     ( ...

最新文章

  1. 2021年大数据Kafka(五):❤️Kafka的java API编写❤️
  2. bind98-内网智能DNS之master服务器构建
  3. idea 文件流读取web-inf下的文件_C#初学者教程系列20:Stream流读写
  4. Perforce 使用说明
  5. 阿里巴巴开源OpenJDK长期支持版本,Java全球管理组织唯一中国企业
  6. linux 编译java并打包
  7. 平均成绩计算机控件,计算机技术基础(第十二章 文件 )
  8. ubuntu 13.04 mysql_Ubuntu13.04 下MySQL5.6安装过程
  9. windows下使用Nginx服务器实现负载均衡方法
  10. 微课|中学生可以这样学Python(1.2节):IDLE环境使用简介
  11. View 绘制体系知识梳理(4) 绘制过程之 Layout 详解
  12. 双层板在哪层覆铜_2020年中国印制电路板行业发展现状及发展趋势预测(图)...
  13. 《Puppet权威指南》——第1章 运维工程师的利器——自动化运维工具
  14. 词根词缀学单词/优秀词典推荐
  15. 欲说还休,欲说还休,却道天凉好个秋
  16. 有个人在偷偷的爱着你
  17. e路航 LH900N地图升级
  18. php网站banner图片切换,最简单的Banner轮播左右切换效果代码及实现思路(附带源码)...
  19. android添加nfc门禁卡,IOS14nfc怎么添加门禁卡?NFC门禁卡教程[多图]
  20. css3-属性选择器 伪类:root :not() :first-of-type :first-child 伪元素 ::first-letter ::first-line ::selection等等

热门文章

  1. 1386: 十转换转R进制
  2. 宝来客:2021年中国珠宝首饰行业市场规模及发展趋势预测分析
  3. 2019年 8月8日 日报
  4. 方块与收纳盒(斐波纳契数列)
  5. 【C#】C#使用OleDb读取Excel出现“外部表不是预期的格式。”
  6. 微信浏览器 苹果 ios 网页跳转没反应
  7. 国考行测答题效率定量推导
  8. Unity特效学习笔记——受击爆点
  9. 科目二考试注意事项(个人笔记)
  10. Nginx 配置静态资源服务器