中缀表达式转后缀表达式并计算——栈
作者:互联网
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