实现逆波兰算法
逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家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的情况我在栈顶上先预先放好一个字符'@',另外该代码是适合输入正确的四则运算的算式,对于错误的算式其结果无法预知。
另外由于在写的几个函数中需要改变主调中的值,我传的都是该值的地址,便于直接修改需要改变的值,也是由于被调需要返回多个值,所以我认为传地址更恰当。
版权声明:本文为博主原创文章,未经博主允许不得转载。