ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

中缀表达式转后缀表达式并计算——栈

2020-05-25 18:02:08  阅读:312  来源: 互联网

标签:中缀 后缀 Opnd Pop break exp postexp 表达式 Optr


X = (56 - 20)*(4 - 3)/(4+2)   ;

那么计算机该怎么算呢?我们给出的方案是先转化为中缀表达式(参考学过的离散),也就是X = 56#20#-4#3#-*4#2#+/  (用#表示一个数据的结束,便于记录)

那接下来怎么办呢?对于后缀表达式的处理我们可以利用栈来进行,把数据放入栈中,每当遇到一个运算符时,便出栈并处理一组数据,同时把这组数据的结果再次存入栈中,直到表达式处理结束,我么也就可以得到最后的结果。

那么问题来了,如何由中缀表达式转换为后缀表达式?

先上代码(PS:书上也有解法与本解法不同(本质一样),可自行参考)

 1 template <class ElemType>
 2 void Trans(char * exp, int n, char * postexp) {    // 中缀转后缀
 3     char e;
 4     SqStack <char> * Optr;            // 定义运算符栈指针 
 5     InitStack(Optr, n);        // 初始化运算符栈 
 6     int i = 0;  
 7     while (*exp != '\0') {
 8         switch (*exp) {
 9         case '(':Push(Optr, '(');        // 左括号进栈 
10             exp++;
11             break;
12         case ')':Pop(Optr, e);            // 右括号元素出栈
13             while (e != '(') {
14                 postexp[i++] = e;
15                 Pop(Optr, e);
16             }
17             exp++;
18             break;
19         case '+':
20         case '-':
21             while (StackEmpty(Optr)) {    // + || -栈不空循环 
22                 GetTop(Optr, e);        // 取栈顶元素 
23                 if (e != '(') {
24                     postexp[i++] = e;    // 将e存放到postexp中 
25                     Pop(Optr, e);
26                 }
27                 else
28                     break;                // 是 '(' 退出循环 
29             }
30             Push(Optr, *exp);            // + || -进栈 
31             exp++;
32             break;
33         case '*':
34         case '/':
35             while (StackEmpty(Optr)) {    // * || /栈不空循环 
36                 GetTop(Optr, e);
37                 if (e == '*' || e == '/') {
38                     postexp[i++] = e;
39                     Pop(Optr, e);
40                 }
41                 else
42                     break;
43             }
44             Push(Optr, *exp); 
45             exp++;
46             break;
47         default:            // 数字字符处理 
48             while (*exp >= '0' && *exp <= '9') {
49                 postexp[i++] = *exp;
50                 exp++;
51             }
52             postexp[i++] = '#';        // 标识一个数字串结束 
53         }
54     }
55     while (StackEmpty(Optr)) {        // exp扫描完毕
56         Pop(Optr, e);
57         postexp[i++] = e;
58     }
59     postexp[i] = '\0';        // 添加结束标识 
60     DestroyStack(Optr);        // 销毁栈 
61 }

简单来说,就是利用运算符的优先级来解决这些问题,对于中缀表达式转化为后缀表达式,我们对运算符的处理是放入一个栈中,当 当前运算符优先级大于栈顶元素优先级时,进栈,反之,不断退栈直到大于栈顶元素优先级为止;对于’(‘我们可以理解为进栈前优先级最高,进栈后优先级最低;

那么为什么要用模板写呢?

接下来我们计算后缀表达式:

 1 template <class ElemType>
 2 double Compvalue(char *postexp, int n) {        // 后缀表达式计算
 3     double a, b, rsh, e;
 4     SqStack <double> * Opnd;        // 操作数栈 
 5     InitStack(Opnd, n);
 6     while (*postexp != '\0') {
 7         switch (*postexp) {
 8         case '+':Pop(Opnd, a);
 9             Pop(Opnd, b);        // + ->出栈两个元素
10             Push(Opnd, a + b);
11             break;                // 元素进栈 
12         case '-':Pop(Opnd, a);
13             Pop(Opnd, b);
14             Push(Opnd, b - a);
15             break;
16         case '*':Pop(Opnd, a);
17             Pop(Opnd, b);
18             Push(Opnd, a*b);
19             break;
20         case '/':Pop(Opnd, a);
21             Pop(Opnd, b);
22             if (a != 0) {
23                 Push(Opnd, b / a);
24                 break;
25             }
26             else {
27                 cout << "除零错误!" << endl;
28                 exit(0);
29             }
30             break;
31         default:            // 数字字符处理
32             rsh = 0;
33             while (*postexp >= '0' && *postexp <= '9') {
34                 rsh = 10 * rsh + *postexp - '0';
35                 postexp++;
36             }
37             Push(Opnd, rsh);    // 进栈 
38             break;
39         }    
40         postexp++;    
41     }
42     GetTop(Opnd, e);
43     DestroyStack(Opnd);
44     return e;
45 }

需要把字符型数字转化为int、double等类型,接下来,按照顺序一个一个处理就可以了;(但是觉得还是有很多代码类似,应该是可以把它合并简化的)

好了,那为什么用模板我们也就知道了,因为我们用了两个栈,一个是char栈,一个是double栈,如果定义两个,那完全是重复了很多代码,所以用模板会好一点,但是还有一个问题,在调用Trans函数和Compvalue函数时,如何实例化呢?显然这也是一个问题。

函数实例化:https://blog.csdn.net/songchuwang1868/article/details/83024484

大家还可以考虑一下表达式的输入问题;

差不多了,附上完整代码:

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<string>
  4 
  5 using namespace std;
  6 
  7 template <class ElemType>
  8 struct SqStack {        // 栈
  9     ElemType *data;
 10     int top;            // 栈顶
 11 };
 12 
 13 template <class ElemType>
 14 void InitStack(SqStack <ElemType> *& s,int length) {    // 初始化
 15     s = (SqStack <ElemType> *)malloc(sizeof(SqStack <ElemType>));
 16     s->data = new ElemType[length];
 17     s->top = -1;
 18 }
 19 
 20 template <class ElemType>
 21 void DestroyStack(SqStack <ElemType> *& s) {        // 销毁
 22     delete[] s->data;
 23     free(s);
 24 }
 25 
 26 template <class ElemType>
 27 bool StackEmpty(SqStack <ElemType> * s) {        // 空 = 0
 28     return (s->top != -1);            // 非空 = 1
 29 }
 30 
 31 template <class ElemType>
 32 void Push(SqStack <ElemType> *& s, ElemType e) {    // 进栈
 33     s->top++;
 34     s->data[s->top] = e;
 35 }
 36 
 37 template <class ElemType>
 38 bool Pop(SqStack <ElemType> *& s, ElemType & e) {     // 出栈
 39     if (s->top == -1)
 40         return false;
 41     e = s->data[s->top];
 42     s->top--;
 43     return true;
 44 }
 45 
 46 template <class ElemType>
 47 bool GetTop(SqStack <ElemType> *& s, ElemType & e) {    // 取栈顶元素
 48     if (s->top == -1)
 49         return false;
 50     e = s->data[s->top];
 51     return true;
 52 }
 53 
 54 template <class ElemType>
 55 void Trans(char * exp, int n, char * postexp) {    // 中缀转后缀
 56     char e;
 57     SqStack <char> * Optr;            // 定义运算符栈指针 
 58     InitStack(Optr, n);        // 初始化运算符栈 
 59     int i = 0;  
 60     while (*exp != '\0') {
 61         switch (*exp) {
 62         case '(':Push(Optr, '(');        // 左括号进栈 
 63             exp++;
 64             break;
 65         case ')':Pop(Optr, e);            // 右括号元素出栈
 66             while (e != '(') {
 67                 postexp[i++] = e;
 68                 Pop(Optr, e);
 69             }
 70             exp++;
 71             break;
 72         case '+':
 73         case '-':
 74             while (StackEmpty(Optr)) {    // + || -栈不空循环 
 75                 GetTop(Optr, e);        // 取栈顶元素 
 76                 if (e != '(') {
 77                     postexp[i++] = e;    // 将e存放到postexp中 
 78                     Pop(Optr, e);
 79                 }
 80                 else
 81                     break;                // 是 '(' 退出循环 
 82             }
 83             Push(Optr, *exp);            // + || -进栈 
 84             exp++;
 85             break;
 86         case '*':
 87         case '/':
 88             while (StackEmpty(Optr)) {    // * || /栈不空循环 
 89                 GetTop(Optr, e);
 90                 if (e == '*' || e == '/') {
 91                     postexp[i++] = e;
 92                     Pop(Optr, e);
 93                 }
 94                 else
 95                     break;
 96             }
 97             Push(Optr, *exp); 
 98             exp++;
 99             break;
100         default:            // 数字字符处理 
101             while (*exp >= '0' && *exp <= '9') {
102                 postexp[i++] = *exp;
103                 exp++;
104             }
105             postexp[i++] = '#';        // 标识一个数字串结束 
106         }
107     }
108     while (StackEmpty(Optr)) {        // exp扫描完毕
109         Pop(Optr, e);
110         postexp[i++] = e;
111     }
112     postexp[i] = '\0';        // 添加结束标识 
113     DestroyStack(Optr);        // 销毁栈 
114 }
115 
116 template <class ElemType>
117 double Compvalue(char *postexp, int n) {        // 后缀表达式计算
118     double a, b, rsh, e;
119     SqStack <double> * Opnd;        // 操作数栈 
120     InitStack(Opnd, n);
121     while (*postexp != '\0') {
122         switch (*postexp) {
123         case '+':Pop(Opnd, a);
124             Pop(Opnd, b);        // + ->出栈两个元素
125             Push(Opnd, a + b);
126             break;                // 元素进栈 
127         case '-':Pop(Opnd, a);
128             Pop(Opnd, b);
129             Push(Opnd, b - a);
130             break;
131         case '*':Pop(Opnd, a);
132             Pop(Opnd, b);
133             Push(Opnd, a*b);
134             break;
135         case '/':Pop(Opnd, a);
136             Pop(Opnd, b);
137             if (a != 0) {
138                 Push(Opnd, b / a);
139                 break;
140             }
141             else {
142                 cout << "除零错误!" << endl;
143                 exit(0);
144             }
145             break;
146         default:            // 数字字符处理
147             rsh = 0;
148             while (*postexp >= '0' && *postexp <= '9') {
149                 rsh = 10 * rsh + *postexp - '0';
150                 postexp++;
151             }
152             Push(Opnd, rsh);    // 进栈 
153             break;
154         }    
155         postexp++;    
156     }
157     GetTop(Opnd, e);
158     DestroyStack(Opnd);
159     return e;
160 }
161 
162 int main()
163 {
164     double temp;
165     string str;
166     cin >> str;
167     char *exp = (char *)str.c_str();
168     char *postexp = new char [str.length()];
169     cout << "中缀表达式为:" << exp << endl;
170     Trans<char>(exp,str.length(),postexp);
171     cout << "转换为后缀表达式为:" << postexp << endl;
172     temp = Compvalue<double>(postexp, str.length());
173     cout << "计算表达式的值为:" << temp << endl;
174     return 0;
175 }
View Code

 

2020-05-25

标签:中缀,后缀,Opnd,Pop,break,exp,postexp,表达式,Optr
来源: https://www.cnblogs.com/2015-16/p/12958259.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有