信息学奥赛一本通 1356:计算(calc)
【题目链接】
ybt 1356:计算(calc)
【题目考点】
1. 表达式求值
中缀表达式求值
2. 表达式树
表达式树:一棵表达式树可以表示一系列的运算。
表达式树中的结点包括运算符与数值
struct Node
{char c;//运算符int n;//数值
}
- 分支结点:c:运算符,n:该子树对应的表达式的值
- 叶子结点:c:
'\0'
,n:数值
表达式树的值,是左子树的值和右子树的值,经过根结点运算符运算后得到的结果。
【解题思路】
解法1:中缀表达式直接求值
- 设数字栈、运算符栈。设数组表示运算符优先级,其中
'('
优先级最高,')'
优先级最低。
从左向右扫描表达式字符串: - 遇到数字时,入数字栈。
- 遇到运算符时,入栈条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是
'('
。只有不满足该条件,则一直出栈。
运算符出栈后,数字栈出栈两个数字,加上刚刚出栈的运算符进行一次运算,将运算结果加入数字栈。
如果要入栈的是')'
且栈顶是'('
,那么二者配对,出栈运算符。否则运算符入栈。 - 扫描结束后若栈中有运算符,都出栈。
- 最后数字栈中的数字即为整个中缀表达式的运算结果
可以预先在字符串末尾加上一个优先级最低的')'
,以促使运算符栈中的运算符都出栈。
解法2:中缀表达式转为后缀表达式,而后求值。
中缀表达式转后缀表达式:
- 设数组保存后缀表达式,设运算符栈。
从左向右扫描表达式字符串: - 遇到数字时,将数字添加到后缀表达式
- 遇到运算符时,入栈条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是
'('
。只有不满足该条件,则一直出栈。出栈的运算符添加到后缀表达式。 - 扫描结束后若栈中有运算符,都出栈,加入后缀表达式。
可以预先在字符串末尾加上一个优先级最低的')'
,以促使运算符栈中的运算符都出栈。
而后求解后缀表达式,后缀表达式的求解方法见:信息学奥赛一本通 1331:【例1-2】后缀表达式的值
解法3:建立表达式树
- 设数字栈、运算符栈。设数组表示运算符优先级,其中
'('
优先级最高,')'
优先级最低。
从左向右扫描表达式字符串: - 遇到数字时,入数字栈。
- 遇到运算符时,入栈条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是
'('
。只有不满足该条件,则一直出栈。
运算符出栈后,数字栈出栈两个数字,加上刚刚出栈的运算符进行一次运算,将运算结果加入数字栈。
如果要入栈的是')'
且栈顶是'('
,那么二者配对,出栈运算符。否则运算符入栈。 - 扫描结束后若栈中有运算符,都出栈。
- 最后数字栈中的数字即为整个中缀表达式的运算结果
可以预先在字符串末尾加上一个优先级最低的')'
,以促使运算符栈中的运算符都出栈。
【题解代码】
解法1:中缀表达式直接求值
#include<bits/stdc++.h>
using namespace std;
#define N 1005
int pri[128];//pri[i]:ascii码为i的运算符的优先级
void initPri()
{pri['('] = 5;pri['^'] = 4;pri['*'] = pri['/'] = 3;pri['+'] = pri['-'] = 2;pri[')'] = 1;
}
int calc(int a, int b, char c)
{switch(c){case '+':return a+b;case '-':return a-b;case '*':return a*b;case '/':return a/b;case '^':return (int)pow(a,b);}
}
int main()
{initPri();//初始化pri数组 int n, num = 0;char s[N];cin >> s;//假设输入的是合法的表达式 int len = strlen(s);s[len] = ')';//取巧,把一个优先级最低的符号')'加到字符串末尾,促使运算符都出栈,以完成最后的计算。 stack<int> nStk;//数字栈 stack<char> cStk;//运算符栈 bool isFormingNum = false;//标志位 表示是否正在构造数字 for(int i = 0; i <= len; ++i)//最后一次取到人为添加的')' {if(s[i] >= '0' && s[i] <= '9')//如果扫描到数字 {isFormingNum = true;num = num * 10 + s[i] - '0';//将字符串转化为数 }else//如果扫描到运算符 {if(isFormingNum)//如果正在构造数字 {nStk.push(num);//将构造好的数字压入数字栈 num = 0;//保存数字的变量复原isFormingNum = false;}while(!(cStk.empty() || pri[s[i]] > pri[cStk.top()] || cStk.top() == '('))//入栈条件:栈空或要入栈的运算符比栈顶的优先级更高或栈顶为左括号。入栈条件取反就是出栈条件。 {int b = nStk.top(); nStk.pop();int a = nStk.top(); nStk.pop();char c = cStk.top(); cStk.pop();nStk.push(calc(a, b, c));}if(cStk.empty() == false && cStk.top() == '(' && s[i] == ')')//如果左右括号配对 cStk.pop();//弹出左括号 不压栈 else cStk.push(s[i]);//运算符压栈 }}cout << nStk.top();//最后栈顶的值就是算式的结果 return 0;
}
解法2:中缀表达式转为后缀表达式,而后求值。
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Node
{int n;char c;
};
Node eq[N];//保存后缀表达式
int p;
int pri[128];//pri[i]:ascii码为i的运算符的优先级
void initPri()
{pri['('] = 5;pri['^'] = 4;pri['*'] = pri['/'] = 3;pri['+'] = pri['-'] = 2;pri[')'] = 1;
}
int calc(int a, int b, char c)
{switch(c){case '+':return a+b;case '-':return a-b;case '*':return a*b;case '/':return a/b;case '^':return (int)pow(a,b);}
}
int solve()//递归求解后缀表达式
{int i = p--;if(eq[i].c){int b = solve(); int a = solve();return calc(a, b, eq[i].c);}elsereturn eq[i].n;
}
int main()
{initPri();//初始化pri数组 int n, num = 0;char s[N];cin >> s;//假设输入的是合法的表达式 int len = strlen(s);s[len] = ')';//取巧,把一个优先级最低的符号')'加到字符串末尾,促使运算符都出栈,以完成最后的计算。 stack<char> cStk;//运算符栈 bool isFormingNum = false;//标志位 表示是否正在构造数字 for(int i = 0; i <= len; ++i)//最后一次取到人为添加的')' {if(s[i] >= '0' && s[i] <= '9')//如果扫描到数字 {isFormingNum = true;num = num * 10 + s[i] - '0';//将字符串转化为数 }else//如果扫描到运算符 {if(isFormingNum)//如果正在构造数字 {eq[++p].n = num;//将构造好的数字加入后缀表达式 num = 0;//保存数字的变量复原isFormingNum = false;}while(!(cStk.empty() || pri[s[i]] > pri[cStk.top()] || cStk.top() == '('))//入栈条件:栈空或要入栈的运算符比栈顶的优先级更高或栈顶为左括号。入栈条件取反就是出栈条件。 {eq[++p].c = cStk.top(); cStk.pop();}if(cStk.empty() == false && cStk.top() == '(' && s[i] == ')')//如果左右括号配对 cStk.pop();//弹出左括号 不压栈 else cStk.push(s[i]);//运算符压栈 }}cout << solve();//求后缀表达式eq的值 return 0;
}
解法3:建立表达式树
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Node
{int val;//数值 char calc;//运算符 int left, right;
};
Node node[N];
int p, num;
int pri[128];
stack<int> nStk;//结点栈
stack<char> cStk;//运算符栈
void initPri()
{pri['^'] = 5;pri['*'] = pri['/'] = 4;pri['+'] = pri['-'] = 3;pri['('] = 6;pri[')'] = 1;
}
int calc(int a, int b, char c)
{switch(c){case '+':return a + b;case '-':return a - b;case '*':return a * b;case '/':return a / b;case '^':return (int)pow(a,b);}
}
int main()
{initPri();string s;cin>>s;s += ')';int num = 0;bool isForming = false;for(int i = 0; i < s.length(); ++i){if(s[i] >= '0' && s[i] <= '9'){num = num * 10 + s[i] - '0'; isForming = true;}else{if(isForming){node[++p].val = num;nStk.push(p);num = 0;isForming = false;}while(!(cStk.empty() || pri[s[i]] > pri[cStk.top()] || cStk.top() == '(')){int pr = nStk.top(); nStk.pop();int pl = nStk.top(); nStk.pop();node[++p].calc = cStk.top(); cStk.pop(); node[p].left = pl, node[p].right = pr;node[p].val = calc(node[pl].val, node[pr].val, node[p].calc);nStk.push(p);}if(cStk.empty() == false && cStk.top() == '(' && s[i] == ')')cStk.pop();elsecStk.push(s[i]); }}int root = nStk.top();cout << node[root].val;return 0;
}
信息学奥赛一本通 1356:计算(calc)相关推荐
- 信息学奥赛一本通1356:计算(calc) (栈)
1356:计算(calc) 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 5797 通过数: 2252 [题目描述] 小明在你的帮助下,破密了Ferrar ...
- 信息学奥赛一本通 1015 计算并联电阻的阻值
传送门
- 信息学奥赛一本通——1012:计算多项式的值
大家好 今天给大家带来<信息学奥赛一本通--1012:计算多项式的值> 看题目: 1012:计算多项式的值 时间限制: 1000 ms 内存限制: 65536 KB 提交数 ...
- 信息学奥赛一本通(基础算法与数据结构-题解汇总目录)
信息学奥赛一本通(C++版)在线评测系统 基础(二)基础算法 更新中...... 第一章高精度计算 1307[例1.3]高精度乘法 1308[例1.5]高精除 1309[例1.6]回文数(Noip ...
- 信息学奥赛一本通 1358:中缀表达式值(expr)
[题目链接] ybt 1358:中缀表达式值(expr) [题目考点] 1. 表达式求值 中缀表达式转后缀表达式 后缀表达式求值 [解题思路] 由于题目要求做中缀表达式转为后缀表达式,而后求值.那么这 ...
- 《信息学奥赛一本通提高篇》第6章 组合数学
例1 计算系数(NOIP2011提高) 信息学奥赛一本通(C++版)在线评测系统 NOIP2011计算系数_nanhan27的博客-CSDN博客 「NOIP2011」 计算系数 - 组合数_TbYan ...
- 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题
第1章 快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章 素数 第 3 章 约数 第 4 章 同余问题 第 5 章 矩阵乘法 第 6 章 ...
- 【例8】合唱队形(《信息学奥赛一本通第五版》)
/* [例8]合唱队形(<信息学奥赛一本通第五版>) http://ybt.ssoier.cn:8088/problem_show.php?pid=1264 [问题描述] N位同学站成一排 ...
- Knight Moves(信息学奥赛一本通-T1450)
[题目描述] 编写一个程序,计算一个骑士从棋盘上的一个格子到另一个格子所需的最小步数.骑士一步可以移动到的位置由下图给出. [输入] 第一行给出骑士的数量 n. 在接下来的 3n 行中,每 3 行描述 ...
最新文章
- 推荐系统的作用和问题
- GUI学习之十四——QAbstractSpinBox学习总结
- flink mysql connector_Flink JDBC Connector:Flink 与数据库集成最佳实践
- 查看 SAP Kyma 上一个 pod 的运行日志
- matlab提速技巧(自matlab帮助文件)
- C++ STL学习笔记 : 2. unordered map 容器
- 一个职场小白想当程序员,该从哪学起?做好三大准备,完全不是问题!
- 【转】用MYSQL都可能会遇到的问题:MYSQL字符数字转换
- anaconda pip 命令报错
- 代码里经常看见idle,是什么意思
- 在Windows上安装Python
- [转载]提升进程权限-OpenProcessToken等函数的用法
- LInux 查看环境变量
- 弱电箱只埋了一根网线时,如何上网和IPTV兼顾?
- onenote使用python开发_我应该用onenote还是印象笔记?
- 盐值加密、公钥秘钥 理解
- 网站被劫持的方式,和检测方法、网站被劫持、检测方法有哪些
- 如何根据视频的宽屏与竖屏来排序?
- ktv服务器几套系统,KTV场所需要哪些设备
- 【Visual C++】游戏开发笔记三十三 浅墨DirectX提高班之二 化腐朽为神奇:DirectX初始化四步曲
热门文章
- Javascript设计模式与开发实践读书笔记(1-3章)
- CentOS 6.4 命令行 安装 VMware Tools
- PHP数组的详细解读
- border-collapse 关于继承问题
- 1947-2020 NBA总冠军次数排行榜
- 开关电源之PCB安规设计规范
- uboot之fastboot烧录镜像
- 鹅厂应届生在600人大群怒怼管理层,反内卷从手撕领导开始......
- 这 6 个开源工具 yyds
- 一群参与境内外赌博网站的开发的程序员被抓,网友:切勿面向监狱编程...