今天总结一下栈的一个重要应用---四则数学表达式的求解

数学表达式的求解是栈的一个重要的应用,在计算机的应用中

如果求解一个四则运算表达式,我们可能会直接写一个程序例如什么printf("%d",a+b)这些类似的简单代码实现加减乘除运算

但如果给你一个这样的表达式:9+(3-1)*3+10/2,这样的表达式对于计算机的困难点是乘除号出现在了加减号的后面,并且加上括号就更加麻烦了,

而只识别01的计算机可能会只按照式子从左往右挨个计算,这就忽略了四则运算表达式的按顺序计算,因此,我们需要设计一种算法来实现对于这类四则运算表达式的求解

我们都知道,对于有左括号的式子一定会有右括号但是有右括号的式子却不一档有左括号,因此我们需要一种储存的数据结构来实现逆序存储和匹配,因此就用了栈这种数据结构;

遇到左括号就进站,出现右括号左括号出战并且让数字参与运算;

但是很遗憾的是,括号也是四则运算式的一部分,有没有一种方法可以让括号不出现在运算式中呢?

答案是有的:

有一种表达式被称为是逆波兰表达式的表达式可以避免括号的出现,这种表达式不需要括号出现,并且是一种后缀表达式

后缀之地方在于运算符是出现在运算数之后的

例如这样的表达式

像这样,就避免了括号的出现,使运算更加简单;

那怎么将中缀表达式转成逆波兰表达式呢?

转换的标准是酱紫的:

碰到数字就输出,如果是运算符先判断与栈顶符号的优先级,是右括号或者优先级小于等于栈顶符号的,将栈顶元素一次输出并且弹栈,并且把当前符号进栈,直到输出后缀表达式;

当然这样说显得很笼统,我总结了一下记忆的方式:

按照这样的法则就可以将中缀表达式转成逆波兰表达式啦;

来举个栗子:9+(3-1)*3+10/2

转化方式和步骤是酱紫的,

我们接下来用代码实现一下:

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 stack<char>q;
  4. 4 string s;
  5. 5 int main()
  6. 6 {
  7. 7 std::ios::sync_with_stdio(false);
  8. 8 cin.tie(0);
  9. 9 cout.tie(0);
  10. 10 getline(cin,s);
  11. 11 for(register int i=0;i<s.size();i++)
  12. 12 {
  13. 13 if(s[i]>='a'&&s[i]<='z')//碰到数字直接输出
  14. 14 cout<<s[i];
  15. 15 else if(s[i]==')')//如果碰到右括号,就找到左括号与它相匹配
  16. 16 {
  17. 17 while(true)
  18. 18 {
  19. 19 if(q.top()=='(')//碰到了就弹栈并且停止
  20. 20 {
  21. 21 q.pop();
  22. 22 break;
  23. 23 }
  24. 24 cout<<q.top();
  25. 25 q.pop();//没找到之前一直弹栈并输出
  26. 26 }
  27. 27 }
  28. 28 else//运算符
  29. 29 {
  30. 30 if(!q.empty()&&(s[i]=='+'||s[i]=='-')&&(q.top()=='*'||q.top()=='/'))//碰到加号或者减号
  31. 31 {
  32. 32 while(!q.empty())
  33. 33 {
  34. 34 if(q.top()=='(')//碰到括号就停止
  35. 35 break;
  36. 36 cout<<q.top();//一直弹栈并输出
  37. 37 q.pop();
  38. 38 }
  39. 39 q.push(s[i]);//当前的元素入栈
  40. 40 }
  41. 41 else
  42. 42 q.push(s[i]);//其余的入栈
  43. 43 }
  44. 44 }
  45. 45 while(!q.empty())
  46. 46 {
  47. 47 cout<<q.top();
  48. 48 q.pop();
  49. 49 }
  50. 50 return 0;
  51. 51 }

逆波兰表达式转化成功了,怎么求逆波兰表达式的值呢:

很简单,从头开始扫描,如果碰到数字就进站,

如果碰到运算符,将栈顶的两个数字出站进行运算,在将结果入栈,一直得到最终的结果;

图解演示一下吧:

相应的用代码实现是灰常简单的:

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 const int num=1e4+10;
  4. 4 char ch[num];
  5. 5 int n;
  6. 6 stack<int>q;
  7. 7 bool operatorpoland(char op)//判段是不是运算符
  8. 8 {
  9. 9 if(op=='+'||op=='-'||op=='*'||op=='/')
  10. 10 return true;
  11. 11 else
  12. 12 return false;
  13. 13 }
  14. 14 int reversepoland()
  15. 15 {
  16. 16 int a,b;
  17. 17 for(register int i=0;i<n;i++)
  18. 18 {
  19. 19 if(!operatorpoland(ch[i]))//如果不是运算符
  20. 20 {
  21. 21 q.push((ch[i]-'0'));//入栈
  22. 22 }
  23. 23 else
  24. 24 {
  25. 25 int a=q.top();//取栈顶两个元素进行运算
  26. 26 q.pop();
  27. 27 int b=q.top();
  28. 28 q.pop();
  29. 29 if(ch[i]=='+')//如果运算符是加号
  30. 30 q.push(a+b);
  31. 31 else if(ch[i]=='-')//如果运算符号是减号
  32. 32 q.push(a-b);
  33. 33 else if(ch[i]=='*')//乘号
  34. 34 q.push(a*b);
  35. 35 else if(ch[i]=='/')//除号
  36. 36 q.push(a/b);
  37. 37 }
  38. 38 }
  39. 39 return q.top();//最后得到栈顶的元素即是结果
  40. 40 }
  41. 41 int main()
  42. 42 {
  43. 43 std::ios::sync_with_stdio(false);
  44. 44 cin>>ch;
  45. 45 n=strlen(ch);
  46. 46 printf("%d",reversepoland());
  47. 47 return 0;
  48. 48 }

可以拿两道题目练练手:

https://acm.sdut.edu.cn/onlinejudge3/contests/3980/problems/F

http://acm.hdu.edu.cn/showproblem.php?pid=1237(水却处理起来有些麻烦)

一会会看情况把没学完的kmp算法给补上;

那就先到这里啦~~~~

关于利用STL栈求解四则中缀表达式以及中缀表达式转逆波兰表达式和逆波兰表达式的求解的更多相关文章

  1. hdu1237 简单计算器[STL 栈]

    目录 题目地址 题干 代码和解释 参考 题目地址 hdu1237 题干 代码和解释 解本题时使用了STL 栈,要记得使用#include<stack>. 解本题时使用了isdigit()函 ...

  2. 从零开始写STL—栈和队列

    从零开始写STL-栈和队列 适配器模式 意图:将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 主要解决:主要解决在软件系统中,常常要将 ...

  3. C++表达式求值(利用数据结构栈)

    唉,刚刚用C++又又一次写了一个较完好的表达式求值程序,最后精简后程序还不到100行.这不经让我 想到了大一上学期刚学c语言时自己费了好大的劲,写了几百行并且功能还不是非常齐全(当时还不能计算有括号的 ...

  4. STL栈的应用之表达式求值

    #include<iostream> #include<cstring> #include<cstdio> #include<stack> using ...

  5. ACM YTU 十进制与八进制的转换 (栈和队列) STL栈调用

    十进制与八进制的转换(栈和队列) Description 对于输入的任意一个非负十进制整数,利用栈打印输出与其等值的八进制数. Input 111 Output 157 Sample Input 14 ...

  6. 利用顺序栈解决括号匹配问题(c++)-- 数据结构

    题目: 7-1 括号匹配 (30 分)   给定一串字符,不超过100个字符,可能包括括号.数字.字母.标点符号.空格,编程检查这一串字符中的( ) ,[ ],{ }是否匹配. 输入格式: 输入在一行 ...

  7. C++ STL栈和队列

    在C++标准库(STL)中,实现了栈和队列,方便使用,在这里我整理了一下笔记,作简要介绍. 1,栈(stack): 头文件 : #include<stack> 定义栈 :stack< ...

  8. 十进制--->二进制(利用C++栈功能)

    原创 十进制转二进制很简单,其中用到C++的栈功能就能更加方便! stack<int> s; //栈的定义,s已经被定义为一个栈 s.push(); //将20入栈 s.push(); s ...

  9. hdu1702 ACboy needs your help again![简单STL 栈 队列]

    目录 题目地址 题干 代码和解释 参考 题目地址 hdu1702 题干 代码和解释 本题很简单,只要掌握STL stack和STL vector的语法即可作答.记录本题是为了记录STL vector的 ...

随机推荐

  1. java-面向对象相关

    public class DemoMethodOverload { public static void main(String[] args) { int[] array = new int[]{1 ...

  2. java-web中的Filter&Listener

    Filter过滤器 当访问服务器资源的时候,过滤器可以将i气你个球拦截下来,完成一些特殊的功能 过滤器的作用: 一般用于完成通用的操作,如验证登陆,统一的编码处理,敏感字符过滤.就是打游戏骂人,会出现 ...

  3. SpringCloud个人笔记-02-Feign初体验

    项目结构 sb_cloud_product <?xml version="1.0" encoding="UTF-8"?> <project x ...

  4. Effective Java —— 多字段下考虑使用建造者模式构建实例

    本文参考 本篇文章参考自<Effective Java>第三版第二条"Consider a builder when faced with many constructor pa ...

  5. 4.4 ROS节点名称重名

    4.4 ROS节点名称重名 场景:ROS 中创建的节点是有名称的,C++初始化节点时通过API:ros::init(argc,argv,"xxxx");来定义节点名称,在Pytho ...

  6. Blazor组件自做五 : 使用JS隔离封装Google地图

    Blazor组件自做五: 使用JS隔离封装Google地图 运行截图 演示地址 正式开始 1. 谷歌地图API 谷歌开发文档 开始学习 Maps JavaScript API 的最简单方法是查看一个简 ...

  7. cali1e4a9cee8dc这是什么东西?

    //我们查下k8s node节点,发现很多类似 cali7c620a7a67b 这样的类似网络设备的东西.//这些是什么呢?//k8s集群节点ht10,node网络情况.[root@ht10 cali ...

  8. 二进制免安装方式,配置mysql

    mysql 5.7.22版本 二进制包安装方法 环境标准化采样: 检查系统内是否有其他mysqlrpm -qa | grep mysql 是否存在mysql用户和用户组grep mysql /etc/ ...

  9. 2019-2020 10th BSUIR Open Programming Championship. Semifinal

    2019-2020 10th BSUIR Open Programming Championship. Semifinal GYM链接https://codeforces.com/gym/103637 ...

  10. 基于Composer的Laravel扩展包开发工作流 ,实现laravle项目的文件管理(记录成长)

    PHP Composer包开发 基于Composer的Laravel扩展包开发工作流 实现laravle项目的文件管理,添加文件/文件夹,删除文件,查看代码/文件(代码支持缩进,支持语法高亮) com ...