什么叫中缀表达式?
我们从小学开始学的那种算式,比如(1+2)*7 就是一个中缀表达式。
当任意一个中缀表达式“加满”括号,例如:
96/12+4*2 →加满括号→ ((96/12)+(4*2)) →逐步拆括号 →生成一个二叉树。
这个树是有规律的:操作符号(+-*/)都在非叶子节点上,且上一层的节点后算,下一层的节点先算。
对这个树进行先序遍历,所得到的序列就是前缀表达式 :+./.96.12.*.4.2
对这个树进行后续遍历,所得到的的序列就是后缀表达式:96.12./.+.4.2.* ,也叫逆波兰式
需要注意的是:人在算数的时候习惯中缀表达式,但是计算机里的表达式求值往往是用后缀表达式做的。
中缀表达式求值的过程
中缀表达式的求值算法是用两个栈去实现的,一个栈记录数字、一个栈记录操作符
粗糙的想法:现在有一个字符串类型的表达式data输入,从第一个位置开始扫描直到遇到\0。中间遇到数就直接压入数字栈。
遇到操作符则要进行判断:当前要进入的操作符如果比操作符栈(下面简称optr)的栈顶元素的运算级别低或者相同,那么就把optr的栈头运算做了,取数字栈的头两个数字进行计算。否则(当前算符的运算级高),压入栈。
遇到左括号无条件压入栈,遇到右括号处理optr里的操作符直到左括号弹出。
当这次循环完成之后,栈中剩余的元素的运算顺序按照从栈顶到尾的顺序进行一次,最后得到的数字就是结果。
精确的代码
/*输入一个正确的中缀表达式,输出他的值*/
/*
测试用例:
96/12+4*2
(3*4+5)/2+1
360/(70-4*16)
158-(27+54)/9
23+((2*3-2)/4+34*5/7+108/9)
*/
#include "stdio.h"
#include "stdlib.h"
#include "stack.h"
int levOptr(int data);
void doOptr(stack* num,stack* optr);
int main0()
{
printf("请输入表达式: \n");
char data[99] ;
scanf("%s",data);
getchar();
int i =0 ;
int val = 0;
stack* num = initStack(NULL,0);
stack* optr = initStack(NULL,0);
for(i=0;data[i] != '\0';i++)
{
if(data[i] == '+' ||
data[i] == '-' ||
data[i] == '*' ||
data[i] == '/' ||
data[i] == '(' ||
data[i] == ')' )
{
//---------------canPush
if(empty(optr) || data[i] == '(')
{
push(optr,data[i]);
}
else if(levOptr(data[i]) > levOptr(optr->next->data) )
{
push(optr,data[i]);
}
//------------canPush OVER------------------
else if(data[i] == ')')
{
while(optr->next->data != '(')
{
if(optr->next == NULL)
return 1;
doOptr(num,optr);
}
pop(optr);
}
else
{
doOptr(num,optr);
push(optr,data[i]);
}
}
else if (data[i]<='9' && data[i]>= '0')
{
val = 0 ;
//getData
for(i ; data[i] != '\0' && (data[i]<='9' && data[i]>= '0');i++)
{
if(data[i]<='9' && data[i]>= '0')
val = val *10 +data[i] - '0';
}
i--;
push(num,val);
//getData Over
}
else
{
return 1;
}
}
while(optr ->data != 0)
{
doOptr(num,optr);
}
printf("最终的结果是 : %d \n" ,num->next ->data);
return 1;
}
int levOptr(int data)
{
if(data == (int )'+' || data == (int)'-')
return 1;
if(data == (int )'*' || data == (int)'/')
return 2;
return 0;
}
void doOptr(stack* num,stack* optr)
{
if(optr->next->data == '(')
{
pop(optr);
return ;
}
int num1 ; int num2 ; int res;
num2 = pop(num);
num1 = pop(num);
int type = optr->next->data;
if(type == (int) '+')
res = num1 +num2 ;
if(type == (int) '-')
res = num1 -num2;
if(type == (int) '*')
res = num1 *num2;
if(type == (int) '/')
{
if(num2 == 0 )
return ;
else
res = num1 / num2;
}
push(num,res);
pop(optr);
}