栈的应用(表达式求值)

首先我们日常见到的表达式是下面这个样子的

((1+2)*5+1)/4;
诸如此类的式子叫做中缀表达式这种表达式是基于人的思维方式
运算符号在两个要运算的数字中间,但是这并不利于计算机的计算,
计算机只需要知道要运算那两个数字和运算符号就好,
所以我没们在这里可以利用后缀表达式(也称逆波兰式)后缀表达式子		   
是如下样子
	1#2+#5#*1+#4/     // #用于分隔两个数字
	那么写成这样有什么优点呢?
     (1).操作符位于操作数之后;
     (2).没有括号;
     (3).操作符没有优先级;

那么我们怎样将一个中缀表达式转化为后缀表达式呢?
在这里我们就需要用到栈的特性(后入先出)

中缀表达式转后缀表达式

开辟:操作符栈 stack<char>oc、结果字符串ans[];

(1).操作数压到结果字符串;操作符玉如操作符栈;

(2).当待压入操作符栈的操作符优先级大于栈顶操作符时,直接入栈;

      若小于等于栈顶操作符的话,栈顶操作符加入到结果字符串后面,直到遇到前括号‘(’或者栈顶操作符优先级小于待入栈操作符,最后待入栈操作符入栈;

(3).如果时前‘(’直接入栈;

(4).如果是后‘)’,将栈中操作符依次弹出并压入结果字符串,并弹出前‘(’不加入结果字符串;

根据以上四个步骤,得到的就是后缀表达式;

实现代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stack>
#include<algorithm>
using namespace std;
 
char ans[5000],s[1100];//ans结果字符串,s原串;
 
int cmp(char c) {
    if (c == '(')
	  return 0;
    else if (c == '+' || c == '-')
	 return 1;
    else if (c =='*' || c == '/')
	  return 2;
}
 
double subans(double x , double y , char c) {
    if (c == '+')
	  return x + y;
    if (c == '-')
	  return x - y;
    if (c == '*')
	  return x * y;
    if (c == '/')
	  return x / y;
}
 
int main(void) {
    int T;
    stack<char>oc; //中缀->后缀 操作符栈;
    stack<double>on; //后缀->求值 操作数栈;

scanf("%d", &T);
while(T--) {
    int k = 0;

    while(!oc.empty())  oc.pop();
    while(!on.empty())  on.pop();
    scanf("%s", s);
    
    int len = strlen(s);
    s[len] = '='; 
    //中缀-->后缀;
    for(int i = 0; i <= len; i++) {
        if ((s[i]>='0'&&s[i] <= '9')|| s[i] =='.')
            ans[k++] = s[i];
        else if(s[i] == '+'|| s[i] == '-'|| s[i] == '*'||s[i] == '/') {
            ans[k++] = '#';
            if (oc.empty())
                oc.push(s[i]);
            else {
            	//     2+(3+2*3-2*1)
               while(!oc.empty()&&cmp(oc.top()) >= cmp(s[i])) {
                    ans[k++] = oc.top();
                    oc.pop();
                }
                oc.push(s[i]);
            }
        	
        }
        else if(s[i] == '(') {
            oc.push(s[i]);
        }
        else if(s[i]==')') {
            while(oc.top()!='(') {
                ans[k++] = oc.top();
                oc.pop();
            }
            oc.pop();
        }
        else if(s[i] == '=') {
            while(!oc.empty()) {
                ans[k++] = oc.top();
                oc.pop();
            }
        }
    }
    //ans[k++] = '=';
    //得到后缀表达式 ans;
  //  printf("\n");
   	//puts(ans);

     //后缀表达式求值;
    int pos = 0;  
    for(int i = 0; i < k; i++) {
        pos = 0;
        if (ans[i] >= '0'&& ans[i] <= '9')//对操作数进行操作;
		{
            for(int j=i; j<k; j++) {
                if ((ans[j] >= '0'&& ans[j] <= '9')|| ans[j] == '.')
                    pos++;
                else
                    break;
            }

            double k = 1, sum1 = 0, sum2 = 0;
            for(int j = i + pos - 1; j >= i; j--) {
                if (ans[j] >= '0' && ans[j] <= '9') {
                    sum1 += (ans[j] - '0') * k;
                    k *= 10;
                }
                else if(ans[j] == '.') {
                    sum1 /= k;
                    k = 1;
                    sum2 += sum1;
                    sum1 = 0;
                }
            }
            sum2 += sum1;
            on.push(sum2);  //报操作数压入操作数栈中;
            i += pos - 1;
        }
        else if (ans[i] == '+'||
		ans[i] == '-'|| ans[i] == '*'|| ans[i] == '/') {
            double x = on.top();
			on.pop();
            double y = on.top();
			on.pop();
            on.push(subans(y,x,ans[i]));  //求值,结果仍压入操作数栈;
        }
    }
    printf("%.2lf\n",on.top()); //处理操作数栈中只有一个操作数;
}
return 0;
}
发布了34 篇原创文章 · 获赞 4 · 访问量 738

猜你喜欢

转载自blog.csdn.net/weixin_44824650/article/details/101616157