【题目链接】

ybt 1356:计算(calc)

【题目考点】

1. 表达式求值

中缀表达式求值

2. 表达式树

表达式树:一棵表达式树可以表示一系列的运算。
表达式树中的结点包括运算符与数值

struct Node
{char c;//运算符int n;//数值
}
  • 分支结点:c:运算符,n:该子树对应的表达式的值
  • 叶子结点:c:'\0',n:数值
    表达式树的值,是左子树的值和右子树的值,经过根结点运算符运算后得到的结果。

【解题思路】

解法1:中缀表达式直接求值

  1. 设数字栈、运算符栈。设数组表示运算符优先级,其中'('优先级最高,')'优先级最低。
    从左向右扫描表达式字符串:
  2. 遇到数字时,入数字栈。
  3. 遇到运算符时,入栈条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是'('。只有不满足该条件,则一直出栈。
    运算符出栈后,数字栈出栈两个数字,加上刚刚出栈的运算符进行一次运算,将运算结果加入数字栈。
    如果要入栈的是')'且栈顶是'(',那么二者配对,出栈运算符。否则运算符入栈。
  4. 扫描结束后若栈中有运算符,都出栈。
  5. 最后数字栈中的数字即为整个中缀表达式的运算结果
    可以预先在字符串末尾加上一个优先级最低的')',以促使运算符栈中的运算符都出栈。

解法2:中缀表达式转为后缀表达式,而后求值。

中缀表达式转后缀表达式:

  1. 设数组保存后缀表达式,设运算符栈。
    从左向右扫描表达式字符串:
  2. 遇到数字时,将数字添加到后缀表达式
  3. 遇到运算符时,入栈条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是'('。只有不满足该条件,则一直出栈。出栈的运算符添加到后缀表达式。
  4. 扫描结束后若栈中有运算符,都出栈,加入后缀表达式。
    可以预先在字符串末尾加上一个优先级最低的')',以促使运算符栈中的运算符都出栈。
    而后求解后缀表达式,后缀表达式的求解方法见:信息学奥赛一本通 1331:【例1-2】后缀表达式的值

解法3:建立表达式树

  1. 设数字栈、运算符栈。设数组表示运算符优先级,其中'('优先级最高,')'优先级最低。
    从左向右扫描表达式字符串:
  2. 遇到数字时,入数字栈。
  3. 遇到运算符时,入栈条件为:栈空,或该运算符优先级比栈顶运算符优先级高,或者栈顶是'('。只有不满足该条件,则一直出栈。
    运算符出栈后,数字栈出栈两个数字,加上刚刚出栈的运算符进行一次运算,将运算结果加入数字栈。
    如果要入栈的是')'且栈顶是'(',那么二者配对,出栈运算符。否则运算符入栈。
  4. 扫描结束后若栈中有运算符,都出栈。
  5. 最后数字栈中的数字即为整个中缀表达式的运算结果
    可以预先在字符串末尾加上一个优先级最低的')',以促使运算符栈中的运算符都出栈。

【题解代码】

解法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)相关推荐

  1. 信息学奥赛一本通1356:计算(calc) (栈)

    1356:计算(calc) 时间限制: 1000 ms         内存限制: 65536 KB 提交数: 5797     通过数: 2252 [题目描述] 小明在你的帮助下,破密了Ferrar ...

  2. 信息学奥赛一本通 1015 计算并联电阻的阻值

    传送门

  3. 信息学奥赛一本通——1012:计算多项式的值

    大家好 今天给大家带来<信息学奥赛一本通--1012:计算多项式的值> 看题目: 1012:计算多项式的值 时间限制: 1000 ms         内存限制: 65536 KB 提交数 ...

  4. 信息学奥赛一本通(基础算法与数据结构-题解汇总目录)

    信息学奥赛一本通(C++版)在线评测系统 基础(二)基础算法   更新中...... 第一章高精度计算 1307[例1.3]高精度乘法 1308[例1.5]高精除 1309[例1.6]回文数(Noip ...

  5. 信息学奥赛一本通 1358:中缀表达式值(expr)

    [题目链接] ybt 1358:中缀表达式值(expr) [题目考点] 1. 表达式求值 中缀表达式转后缀表达式 后缀表达式求值 [解题思路] 由于题目要求做中缀表达式转为后缀表达式,而后求值.那么这 ...

  6. 《信息学奥赛一本通提高篇》第6章 组合数学

    例1 计算系数(NOIP2011提高) 信息学奥赛一本通(C++版)在线评测系统 NOIP2011计算系数_nanhan27的博客-CSDN博客 「NOIP2011」 计算系数 - 组合数_TbYan ...

  7. 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题

    第1章   快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章  素数 第 3 章  约数 第 4 章  同余问题 第 5 章  矩阵乘法 第 6 章 ...

  8. 【例8】合唱队形(《信息学奥赛一本通第五版》)

    /* [例8]合唱队形(<信息学奥赛一本通第五版>) http://ybt.ssoier.cn:8088/problem_show.php?pid=1264 [问题描述] N位同学站成一排 ...

  9. Knight Moves(信息学奥赛一本通-T1450)

    [题目描述] 编写一个程序,计算一个骑士从棋盘上的一个格子到另一个格子所需的最小步数.骑士一步可以移动到的位置由下图给出. [输入] 第一行给出骑士的数量 n. 在接下来的 3n 行中,每 3 行描述 ...

最新文章

  1. 推荐系统的作用和问题
  2. GUI学习之十四——QAbstractSpinBox学习总结
  3. flink mysql connector_Flink JDBC Connector:Flink 与数据库集成最佳实践
  4. 查看 SAP Kyma 上一个 pod 的运行日志
  5. matlab提速技巧(自matlab帮助文件)
  6. C++ STL学习笔记 : 2. unordered map 容器
  7. 一个职场小白想当程序员,该从哪学起?做好三大准备,完全不是问题!
  8. 【转】用MYSQL都可能会遇到的问题:MYSQL字符数字转换
  9. anaconda pip 命令报错
  10. 代码里经常看见idle,是什么意思
  11. 在Windows上安装Python
  12. [转载]提升进程权限-OpenProcessToken等函数的用法
  13. LInux 查看环境变量
  14. 弱电箱只埋了一根网线时,如何上网和IPTV兼顾?
  15. onenote使用python开发_我应该用onenote还是印象笔记?
  16. 盐值加密、公钥秘钥 理解
  17. 网站被劫持的方式,和检测方法、网站被劫持、检测方法有哪些
  18. 如何根据视频的宽屏与竖屏来排序?
  19. ktv服务器几套系统,KTV场所需要哪些设备
  20. 【Visual C++】游戏开发笔记三十三 浅墨DirectX提高班之二 化腐朽为神奇:DirectX初始化四步曲

热门文章

  1. Javascript设计模式与开发实践读书笔记(1-3章)
  2. CentOS 6.4 命令行 安装 VMware Tools
  3. PHP数组的详细解读
  4. border-collapse 关于继承问题
  5. 1947-2020 NBA总冠军次数排行榜
  6. 开关电源之PCB安规设计规范
  7. uboot之fastboot烧录镜像
  8. 鹅厂应届生在600人大群怒怼管理层,反内卷从手撕领导开始......
  9. 这 6 个开源工具 yyds
  10. 一群参与境内外赌博网站的开发的程序员被抓,网友:切勿面向监狱编程...