实现逆波兰算法

        逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法。按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。 —–取自百度百科

       因为计算机无法像人类一样智能的计算算数表达式,并且即使计算机可以像人类一样计算算式,其耗费的资源与时间是相当大的,所以产生了逆波兰算法。

例如:

中缀表达式                        后缀表达式

1+2                                      1 2+

1+2*3                                  1 2 3*+

(1+2)*3                          1 2 +3*

这就是其运算的原理,将中缀表达式变为后缀表达式,然后再运算,直接从左到右计算,没有中缀表达式那么复杂,为计算机实现复杂的运算提供了可行的方法,下来话不多说,直接上代码:

/*实现逆波兰算法*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int process(char *string);
int calSum(char op,int equation1,int equation2);
int level(char op);
int getEquation(int *stackOfoperand,char *stackOfOperator,int *topOfOperatend,int *topOfOperator);
int main()
{
    char equation[50],*str=equation;
    int result;
    printf("Please enter an equation:\n");
    gets(equation);
    result=process(equation);
    printf("the result is %d\n",result);
    return 0;
}
int process(char *string)
{
    char stackOfOperator[10],op,*p=string;
    int stackOfOperatand[10],topOfOperator=0,topOfOperatand=-1,sum;
    stackOfOperator[topOfOperator]='@';
    while(*p!='\0'){  //遍历算式
        if(*p>='0'&&*p<='9'){   //遇到字符数先转换为整型数再存入操作数的栈中
            sum=0;
            while(*p>='0'&&*p<='9'){
                sum=sum*10+(*p-'0');
                p++;
            }
            stackOfOperatand[++topOfOperatand]=sum; //操作数入栈
        }
            if(*p=='+'||*p=='-'||*p=='*'||*p=='/') //当遇到操作符时,将算式中的操作符与操作符栈中的操作符相比再
            {
                while(level(*p)<=level(stackOfOperator[topOfOperator]))
                { //当算式中的操作符的优先级比操作符栈中的低时,栈中的操作符出栈并计算
                    stackOfOperatand[topOfOperatand]=getEquation(stackOfOperatand,stackOfOperator,&topOfOperatand,&topOfOperator);
					topOfOperator--;
                }
                stackOfOperator[++topOfOperator]=*p++;//当算式中的操作符比操作符栈中的高时直接入栈
            }
              else if(*p=='(')  stackOfOperator[++topOfOperator]=*p++; //当是左括号时直接入栈
                 else{
                   if(*p==')'){ //当遇到右括号时前面必有左括号,计算到左括号
                    while(stackOfOperator[topOfOperator]!='('){
                    stackOfOperatand[topOfOperatand]=getEquation(stackOfOperatand,stackOfOperator,&topOfOperatand,&topOfOperator);
                    topOfOperator--;
					}
					topOfOperator--;//左括号出栈
                    p++;//指针指向下一个算式中的字符
                }
                 }
    }
    while(stackOfOperator[topOfOperator]!='@'){ //当跑完字符算式时,将操作符栈跑完的时候操作数栈也跑完了
            stackOfOperatand[topOfOperatand]=getEquation(stackOfOperatand,stackOfOperator,&topOfOperatand,&topOfOperator);
			topOfOperator--;
    }
    return stackOfOperatand[topOfOperatand];
}
int calSum(char op,int equation1,int equation2)
{
    switch(op){ //遇到操作数计算之后直接返回,不用break
    case '+':return equation2+equation1; //算式二是左操作数,算式一是右操作数
    case '-': return equation2-equation1;
    case '*':return equation2*equation1;
    case '/':return equation2/equation1;
    }
}
int level(char op) //比较运算符的优先级
{
    switch(op){
    case '*':
    case '/': return 3;
    case '+':
    case '-': return 2;
    case '(': return 1;
    case '@': return 0;
    }
}
int getEquation(int *stackOfOperand,char *stackOfOperator,int *topOfOperand,int *topOfOperator)
{
    char op;
    int operand1,operand2;
    op=stackOfOperator[*topOfOperator];
    operand1=stackOfOperand[*topOfOperand];
	*topOfOperand=*topOfOperand-1;
    operand2=stackOfOperand[*topOfOperand];
    return calSum(op,operand1,operand2);
} 

     我将操作符和操作数放在了两个栈中,其中在操作符栈进入之前放了一个字符’@’并且通过level函数返回0,因为左括号直接入栈的情况比较特殊,如果第一个是左括号的话,为了避免再讨论当topOfOpertor等于-1和不为-1的情况我在栈顶上先预先放好一个字符’@’,另外该代码是适合输入正确的四则运算的算式,对于错误的算式其结果无法预知。

另外由于在写的几个函数中需要改变主调中的值,我传的都是该值的地址,便于直接修改需要改变的值,也是由于被调需要返回多个值,所以我认为传地址更恰当。


点赞