基本计算器的初步实现——将表达式转换成逆波兰表达式并计算结果

在这里插入图片描述
作为栈的初学者,表达式求值的问题给我带来了非常多的思考。目前,我还只能实现非负整数的带加减乘除模及括号运算的表达式求值,且效率也不算高。但还是想记录一下这个问题实现的整个过程。

我们平常习惯的表达式称为中缀表达式,是语法树中序遍历的结果,这样用计算机来计算并不容易,特别是遇到括号中还有很多括号的情况。也就是说,我们面对的最大的问题是,当不知道有多少个优先级需要判断时,我们到底该怎么办呢?前人真的非常的聪明,想到转换成后缀表达式进行求值,而这个转换的过程让我颇有受益。

在所有问题之前,我们先确定符号的优先级。

int priority(char op){
 if(op == '+' || op == '-') return 1;
 else if(op == '*' || op == '/' || op == '%') return 2;
 else return 0;
}//运算符优先级。

接下来我们先实现中缀表达式到后缀表达式的转换。

创建

    char* op = (char*)malloc(sizeof(char)*1000000);
    char** RPN = (char**)malloc(sizeof(char*)*1000000);
    int i = 0, j = 0, k, t = 0, top = -1;//op为我们储存符号的栈,RPN为我们要转换成的逆波兰表达式。

对所有可能遇到的字符进行处理

if(s[k] == 32) continue;//说明:s为传入的表达式字符串,k为已经遍历到的第k位字符。
//如果是空格我们直接跳过。

 else if(s[k] >= '0' && s[k] <= '9'){
         RPN[j] = (char*)malloc(sizeof(char)*20);
         RPN[j][t] = s[k];
         t++;
         while(k+1 < strlen(s) && s[k+1] >= '0' && s[k+1] <= '9'){
            RPN[j][t] = s[k+1];
             t++;
             k++;
            }
            RPN[j][t] = '\0';
            j++;
            t = 0;
        }//我们用j来记录逆波兰表达式中元素的个数。如果是非负整数,我们直接将其放入逆波兰表达式中,我们其实关键的是要处理符号的顺序

 else if(s[k] == '('){
         top++;
         op[top] = s[k];
        }//如果遇到左括号,我们需要将其放入符号的栈中,以来判断接下来符号入逆波兰表达式的顺序,括号中运算符应该优先入逆波兰表达式,先进行计算。

while(s[k] == '+' || s[k] == '-' || s[k] == '*' || s[k] == '/' || s[k] == '%'){
    if(top == -1 || op[top] == '(' || priority(s[k])>priority(op[top])){
     top++;
     op[top] = s[k];
     break;
    }//如果表达式右边的运算符优先级高,进入符号栈,出栈时会优先左边先进的符号。
    else{
     RPN[j] = (char*)malloc(sizeof(char)*2);
     RPN[j][0] = op[top];
     RPN[j][1] = '\0';
     j++;
     top--; 
    }//将运算级高的符号优先入逆波兰表达式,先进行计算。
    }

if(s[k] == ')'){
    while(op[top]!='('){
     RPN[j] = (char*)malloc(sizeof(char)*2);
     RPN[j][0] = op[top];
     RPN[j][1] = '\0';
     j++;
     top--;
    }//将括号中的运算符提前出栈,确保其优先级最高。
    top--;  //舍弃左括号。 
   }   

while(top!=-1){
    RPN[j] = (char*)malloc(sizeof(char)*2);
    RPN[j][0] = op[top];
    RPN[j][1] = '\0';
    j++;
    top--;
   }    //遍历完表达式之后,将符号栈中的运算符出栈进入逆波兰表达式。      

转换成逆波兰表达式之后,问题变得简单,我们只要遍历逆波兰表达式,遇到符号,将其前面的两个数进行运算即可。最后进行逆波兰表达式求值

创建

    int *stack;
    stack = (int*)malloc(sizeof(int) * j);
    top = 0;//之前定义过top了,这里直接归0,创建一个储存整数的栈,直到遇到符号我们再进行运算。

处理每一个运算符

    for(i = 0; i < j; i++){
        if((RPN[i][0] >= '0' && RPN[i][0] <= '9') || RPN[i][1] != '\0'){
            stack[top] = atoi(RPN[i]);
            top++;
        }//如果是数,直接进入整数栈进行储存。
  else{
            switch(RPN[i][0]){
                case '*':
                    stack[top-2] = stack[top-1] * stack[top-2];
                    break;
                case '/':
                    stack[top-2] = stack[top-2] / stack[top-1];
                    break;
                case '%':
                    stack[top-2] = stack[top-2] % stack[top-1];
                    break;                    
                case '+':
                    stack[top-2] = stack[top-2] + stack[top-1];
                    break;
                case '-':
                    stack[top-2] = stack[top-2] - stack[top-1];
                    break;
                default:
                    break;
            }
            top--;
        }
        
    }//遇到符号就对前两个非负整数进行运算。
    
    return stack[0];//输出最后的结果。

当然这个计算器,目前还无法进行包含负整数的运算以及一些其他简单的功能,在效率方面也会继续学习一下再进行改进。进行前行咯。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值