其他分享
首页 > 其他分享> > 中缀表达式转后缀表达式并计算——栈

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

作者:互联网

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