用栈实现算术表达式的运算,需要两个栈:一个用于保存操作数,一个用于保存操作码(运算符)。基本的操作
过程是:(1)定义一个栈,这里用数组实现。说明两两个栈:numStack,opStack.
(2)对表达式进行扫描:
- 如果是操作数直接进入操作数栈。
- 如果是操作向右的小括号,直接入栈。
- 如果是操作码,操作栈为空时,直接入栈。如果不空,弹出栈顶操作码,和当前的操作码比较优先级, 如果低于当前操作码,则弹出的操作码和当前的操作码先后入栈。如果不低于当前操作码,从操作数栈弹出二个操作数,用之前弹出的操作符进行运算(注意操作数先后顺序),结果入操作数栈。继续弹操作码栈,和当前操作码 比较,重复前面的处理方法,直到遇见低的操作码或操作码栈空,当前操作码入操作码栈。
- 如果遇到向左的小括号),直接弹出栈顶操作码和两个操作数,运算,结果入操作数栈,继续弹操作码和操作数,直到遇见向右的(,继续检查下一个表达式元素。
按上述步骤,直到表达的所以元素处理完毕。
下面是代码:该程序可以完成:加、减、乘、除和求余运算(+,-,* ,/,%),可以使用()改变优先级顺序。按浮点float类型运算。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct
{
char *pStr[MAX_SIZE];
int top;
} STACK;
STACK numStack,opStack;
void initStack()
{
opStack.top=-1;
numStack.top=-1;
}
int push(char *num,STACK *stack)
{
if (stack->top>=MAX_SIZE-1)
return -1;
stack->top++;
stack->pStr[stack->top]=num;
return 0;
}
int pop(char **num,STACK *stack)
{
if (stack->top<0)
return -1;
*num=stack->pStr[stack->top];
stack->top--;
return 0;
}
//比较优先级:return 1:op1>=op2, -1:op1<op2
int cmpPriority(char *op1,char *op2)
{
int p=1;
if ((strcmp(op1,"+")==0||strcmp(op1,"-")==0)&&(strcmp(op2,"*")==0||strcmp(op2,"/")==0||strcmp(op2,"%")==0))
p=-1;
return p;
}
void compute(char *num1,char *num2,char* op,char **value)
{
char *str;
float n1,n2,tmp;
float result;
int f=1;
n1=(float)atof(num1);
n2=(float)atof(num2);
if (strcmp(op,"+")==0)
result=n1+n2;
else if (strcmp(op,"-")==0)
result=n1-n2;
else if (strcmp(op,"*")==0)
result=n1*n2;
else if (strcmp(op,"/")==0)
result=n1/n2;
else if (strcmp(op,"%")==0)
result=(float)((int)n1%(int)n2);
tmp=result;
while (tmp/10) {f++;tmp=tmp/10;}
str=(char*)malloc(f+8); //可以保存到小数点后六位。
sprintf(str,"%.6f",result); //浮点数转为字符串。小数点后保留六位
*value=str;
}
//从字符串str中提取一个运算单元,返回1:数值,返回2:操作符。*start开始位置值,返回结束位置值,*subStr:返回串指针。
int getElement(char *str,int *start,int *type,char **subStr)
{
int ret=0;
unsigned i;
*subStr=NULL;*type=1;
for (i=*start;i<strlen(str);i++)
{
if (str[i]=='('||str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='%'||str[i]=='('||str[i]==')')
{
*subStr=(char*)malloc(2);
(*subStr)[0]=str[i];(*subStr)[1]='\0';
*type=2;
*start=i+1;
break;
}
else if (str[i]>='0'&&str[i]<='9')
{
int count=1,i0=i;
i++;
while ((str[i]>='0'&&str[i]<='9')||str[i]=='.') {i++;count++;}
*start=i++;
*subStr=(char*)malloc(count+1);
strncpy(*subStr,str+i0,count);(*subStr)[count]='\0';
*type=1;
break;
} else {ret=-1;break;}
}
return ret;
}
void main()
{
char *result=0;
char ops[MAX_SIZE]="5*6.7-(60.8-21.5)*2",*subStr;
int re,status=0;
char *c=NULL,*c0;
char *num1,*num2;
int type=1,start=0;
initStack();
printf("请输入计算式:");
gets(ops);
status=getElement(ops,&start,&type,&subStr);
while (subStr!=NULL&&status>=0)
{
if (type==2)
{
if (opStack.top>=0)
{
if (strcmp(subStr,"(")==0)
push(subStr,&opStack);
else if (strcmp(subStr,")")==0)
{
pop(&c0,&opStack);
if (strcmp(c0,"(")!=0)
{
status=pop(&num2,&numStack);
if (status<0) break;
status=pop(&num1,&numStack);
if (status<0) break;
compute(num1,num2,c0,&result);
push(result,&numStack);
free(num1);free(num2);free(c0);
continue;
}
}
else
{
pop(&c0,&opStack);
if (strcmp(c0,"(")==0)
{
push(c0,&opStack);push(subStr,&opStack);
}
else if ((re=cmpPriority(c0,subStr))>0)
{
status=pop(&num2,&numStack);
if (status<0) break;
status=pop(&num1,&numStack);
if (status<0) break;
compute(num1,num2,c0,&result);
push(result,&numStack);
free(num1);free(num2);free(c0);
continue;
}
else {push(c0,&opStack);push(subStr,&opStack);}
}
} else push(subStr,&opStack);
} else push(subStr,&numStack);
status=getElement(ops,&start,&type,&subStr);
}
while (opStack.top>=0&&status>=0)
{
pop(&c,&opStack);
status=pop(&num2,&numStack);
if (status<0) break;
status=pop(&num1,&numStack);
if (status<0) break;
compute(num1,num2,c,&result);
free(num1);free(num2);free(c);
push(result,&numStack);
}
if (numStack.top==0)
pop(&result,&numStack);
else status=-1;
if (status>=0) {
printf("Result=%s\n",result);
}
else printf("表达式中有错误.\n");
}
经测试,能正确完成运算。