算法学习记录-栈的应用--表达式运算

前面做了栈的基本操作

总感觉需要做一个实际的例子来检验一下。

这里我将用栈来做一个简单的四则运算。

目标比较简单:

做一个带小括号(“()”)的四则运算,如果要加入到中括号(“[]”)或者大括号(“{}”),依次类推。

求一个表达式:

用下面这个算是做例子,程序最后应该可以算出任何带小括号的运算。

3+(32-6)*9+5*3-(3*(65-15)/5)+12;

方法一:后缀法。

1.了解中缀和后缀表示法

中缀表示法:刚才的那个算是就是中缀表示法,我们通常看到的数学符号就是中缀表示法,即数字在计算符号的两边。

后缀表示法:所有的计算符号在数字之后。不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行。

原理:从左到右遍历表达式,如果是数字则输出,如果是符号:判断该符号与栈顶的符号优先级,

    如果是右括号或者优先级低于栈顶符号,则栈中元素依次出栈并输出,并且将当前符号进栈。

对上面的式子进行处理:

后序表达式用处

当转换成后序表达式后更方便计算表达式的值,如将后序表达式的元素依次进栈直到遇到运算符,这时候从栈中弹出两个元素,再结合运算符计算出这两个数运算的结果(如6-9=3),将其结果压栈(此时栈元素为3 23 -3),然后继续将后序非符号元素压栈,直到遇到运算符。重复之前的操作。。。

InfixExp(中序表达式)转换PostfixExp(后序表达式)算法

1)当输入的是操作数时候,直接输出到后序表达式PostfixExp序列中

2)当输入开括号时候,把它压栈

3)当输入的是闭括号时候,先判断栈是否为空,若为空,则发生错误并进行相关处理。若非空,把栈中元素依次弹出并输出到Postfix中,知道遇到第一个开括号,若没有遇到开括号,也发生错误,进行相关处理

4)当输入是运算符op(+、- 、×、/)时候

a)循环,当(栈非空and栈顶不是开括号and栈顶运算符的优先级不低于输入的运算符的优先级)时,反复操作:将栈顶元素弹出并添加到Postfix中

b)把输入的运算符op压栈

5)当中序表达式InfixExp的符号序列全部读入后,若栈内扔有元素,把他们依次弹出并放到后序表达式PostfixExp序列尾部。若弹出的元素遇到空括号,则说明不匹配,发生错误,并进行相关处理

编写了一个程序如下: 比较烂

  1 #include <iostream>
  2 #include <string>
  3 #include <vector>
  4 #include <stack>
  5
  6 using namespace std;
  7
  8 int get_proi(char ch)
  9 {
 10     switch(ch)
 11     {
 12     case ‘+‘:
 13     case ‘-‘:return 1;
 14
 15     case ‘*‘:
 16     case ‘/‘:return 2;
 17
 18     case ‘(‘:
 19     case ‘)‘:return 3;
 20     }
 21 }
 22
 23 void predo(string &str)
 24 {
 25     string ot;
 26     int k=0;
 27     for (int i=0;i<str.size();i++)
 28     {
 29         if (isdigit(str[i]) || isspace(str[i]) ||
 30             str[i] == ‘+‘ || str[i] == ‘-‘ || str[i] == ‘*‘ || str[i] == ‘/‘ ||
 31             str[i] == ‘(‘ || str[i] == ‘)‘)
 32         {
 33             ot.push_back(str[i]);
 34         }
 35     }
 36     str = ot;
 37 }
 38
 39 bool in_to_pre(string &str,vector<string> &vec)//中序-->后序
 40 {
 41     vector<string> dest;
 42     stack<string> opstack;
 43     bool flag = false;
 44     int k=0;
 45     int i=0;
 46     //get every elem
 47     while(i<str.size())
 48     {
 49         i=k;
 50         string elem;
 51         if (isdigit(str[i]))
 52         {
 53             while(i<str.size() && isdigit(str[i]))
 54             {
 55                 elem.push_back(str[i]);
 56                 i++;
 57             }
 58             k = i;
 59             vec.push_back(elem);
 60         }
 61         else if (str[i] == ‘+‘ || str[i] == ‘-‘ || str[i] == ‘*‘ || str[i] == ‘/‘ || str[i] == ‘(‘ || str[i] == ‘)‘)
 62         {
 63             elem.push_back(str[i]);
 64             vec.push_back(elem);
 65             i++;
 66             k = i;
 67         }
 68     }
 69     // in to pre
 70     int deep = 0;
 71     for (vector<string>::iterator it = vec.begin();it!=vec.end();it++)
 72     {
 73         string tmp = *it;
 74
 75         if (isdigit(tmp[0]))
 76         {//1如果是数字直接放入dest中
 77             dest.push_back(tmp);
 78         }
 79         else
 80         {//2如果是操作符则需要判断
 81             //2.1.如果是 “(”,压栈op
 82             if (tmp[0] == ‘(‘)
 83             {
 84                 opstack.push(tmp);
 85                 deep++;
 86             }
 87             //2.2.如果是 “)”,出栈直到“(”
 88             else if (tmp[0] == ‘)‘)
 89             {
 90                 while(!opstack.empty() && opstack.top().at(0) != ‘(‘)
 91                 {
 92                     dest.push_back(opstack.top());
 93                     opstack.pop();
 94                 }
 95                 if (opstack.empty())
 96                 {
 97                     return -1;
 98                 }
 99                 else
100                 {
101                     deep--;
102                     opstack.pop();
103                 }
104             }
105             //3.不是括号
106             //3.1 循环,当(栈非空 and 栈顶不是开括号 and 栈顶运算符的优先级 不低于 输入的运算符的优先级)时,反复操作:将栈顶元素退出压入后序栈中
107             else if (!opstack.empty() && opstack.top().at(0) != ‘(‘ && get_proi(opstack.top().at(0)) >= get_proi(tmp[0]))
108             {
109                 while(!opstack.empty() && opstack.top().at(0) != ‘(‘ && get_proi(opstack.top().at(0)) >= get_proi(tmp[0]))
110                 {
111                     dest.push_back(opstack.top());
112                     opstack.pop();
113                 }
114                 opstack.push(tmp);
115             }
116             //3.2 压入 操作符 栈中
117             else
118             {
119                 opstack.push(tmp);
120             }
121         }
122     }
123     while(!opstack.empty())
124     {
125         dest.push_back(opstack.top());
126         opstack.pop();
127     }
128     if (deep != 0)
129     {
130         return -1;
131     }
132     else
133     {
134         vec = dest;
135         return 1;
136     }
137 }
138
139 string cacl(string str1,string str2,string op,stack<string> &opt)
140 {
141     char oo = op.at(0);
142     double num1 = atof(str1.c_str());
143     double num2 = atof(str2.c_str());
144     double sum=0;
145     switch(oo)
146     {
147     case ‘+‘:sum =  num1+num2;break;
148     case ‘-‘:sum =  num1-num2;break;
149     case ‘*‘:sum =  num1*num2;break;
150     case ‘/‘:sum =  num1/num2;break;
151     }
152
153     char t[256];
154     string s;
155
156     sprintf(t, "%f", sum);
157     s = t;
158     return s;
159 }
160
161 void do_cacl(vector<string> &vec)
162 {
163     stack<string> opt;
164     for (vector<string>::iterator it = vec.begin();it!=vec.end();it++)
165     {
166         string tmp = *it;
167         if (isdigit(tmp[0]))
168         {
169             opt.push(tmp);
170         }
171         else
172         {
173             string str2 = opt.top();
174             opt.pop();
175             string str1 = opt.top();
176             opt.pop();
177
178             opt.push(cacl(str1,str2,tmp,opt));
179         }
180     }
181     cout<<opt.top();
182 }
183 int main()
184 {
185     string in;
186     getline(cin,in);
187     predo(in);
188     //not use negative
189     vector<string> vecpre;
190     in_to_pre(in,vecpre);
191
192     do_cacl(vecpre);
193
194
195     return 0;
196 }

2.运算的优先级:

算法学习记录-栈的应用--表达式运算

时间: 2024-10-25 12:11:37

算法学习记录-栈的应用--表达式运算的相关文章

算法学习记录-查找——平衡二叉树(AVL)

排序二叉树对于我们寻找无序序列中的元素的效率有了大大的提高.查找的最差情况是树的高度.这里就有问题了,将无序数列转化为 二叉排序树的时候,树的结构是非常依赖无序序列的顺序,这样会出现极端的情况. [如图1]: 这样的一颗二叉排序树就是一颗比较极端的情况.我们在查找时候,效率依赖树的高度,所以不希望这样极端情况出现,而是希望元素比较均匀 的分布在根节点两端. 技术参考:fun4257.com/ 问题提出: 能不能有一种方法,使得我们的二叉排序树不依赖无序序列的顺序,也能使得我们得到的二叉排序树是比

算法学习 - 递归与非递归,位运算与乘除法速度比较

递归调用非递归调用 运行时间比较 结论 位运算与乘除法 结论 递归调用/非递归调用 我们都知道,很多算法,都是用递归实现的.当然它们同时也是可以用非递归来实现. 一般我们在对二叉树进行遍历的时候,还有求斐波那契数的时候,递归是非常简单的.代码容易懂,好实现. 但是递归的时候,有一个问题,就是需要压栈.为什么要压栈呢?因为当我在函数内部调用自身的时候,要中断当前的操作继续跳转到下一次的实现,而当前运行的状态要保存起来.所以就把当前状态进行压栈,等到运行到递归条件结束的时候,再弹栈. 所以递归就是需

KMP算法学习记录----《大话数据结构》部分匹配表学习部分

如需转载,请保留本文链接. 首先先将<大话数据结构>关于KMP算法的讲解部分贴上,本文不提供下载链接,也不会将电子书作为资料留百度云,需要电子书的各位,请自行寻找电子版. 关于上述的KMP算法种的next数组的推导部分,一直不是很明白,本贴是关于上述部分的学习推导记录. 以书中字符串为例: 1|2|3|4|5|6|7|8|9| a|b|a|b|a|a|a|b|a| 0|1|1|2|3|4|2|2|3| string T = "ababaaaba"; int i = 1;j

算法学习_栈

以蓝书为学习参考,进行的栈的学习 例题1: 实现一个栈,支持Push,Pop和GetMin(查询栈中最小的值)在O(1)完成 算法实现思路:建立两个栈,A存原本的数据,B存以栈底开头的每段数据的最小值 Push(X),在A中插入X,在B中插入min(B的栈顶数据,X).执行GetMin只需要输出B.top()即可 例题2: Input 8 I 2 I -1 I 1 Q 3 L D R Q 2 Output 2 3 //对顶栈算法 #include <bits/stdc++.h> using n

【算法学习记录-排序题】【PAT A1012】The Best Rank

To evaluate the performance of our first year CS majored students, we consider their grades of three courses only: C - C Programming Language, M - Mathematics (Calculus or Linear Algrbra), and E - English. At the mean time, we encourage students by e

算法学习 - 最小栈的实现O(1)时间

// //  main.cpp //  MinStack2 // //  Created by Alps on 14/12/3. //  Copyright (c) 2014年 chen. All rights reserved. // #include <iostream> #include <vector> using namespace std; class MinStack { public: vector<int> stack; int min; void p

冒泡算法学习记录

bubblesort.c这是维基百科上的说明,很详细 #include <stdio.h> #include <stdlib.h> #include <time.h> int main(int argc, char *argv[]) {     int arr[10];     srand(time(NULL));     int i;     for (i = 0; i < 10; i ++)         arr[i] = rand() % 100;    

KMP算法学习记录----Jake Boxer博文学习部分

如需转载,请保留本文链接. Jake Boxer 英文博文链接:http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/ 如何使用部分匹配表 1.作用:使用部分匹配表跳过那些已经做过的,旧的比较部分,从非重复匹配部分开始. 2.if(匹配表结果大于1) { 允许跳过的字符数量 = 匹配长度 - 部分匹配表[匹配长度-1]; } else { 允许跳过的字符数量 =  部分匹配表[匹

算法学习记录

1. 时空复杂度分析: O(1).O(n).O(n^2).O(log n).O(n log n)是什么意思 传输门-比较易懂 2. 待更新... 原文地址:https://www.cnblogs.com/412013cl/p/10929806.html