#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define INIT_SIZE 20
#define INCREMENT 10
//创建操作数栈
typedef struct OprdSatck
{
double *top;
double *base;
int stackSize;
}OPRD;
//创建运算符栈
typedef struct OptrStack
{
char *top;
char *base;
int stackSize;
}OPTR;
//创建操作数栈
void InitOprdStack(OPRD *oprd)
{
oprd->base=(double*)malloc(INIT_SIZE*sizeof(double));
if(oprd->base==NULL)
exit(0);
oprd->top=oprd->base;
oprd->stackSize=INIT_SIZE;
}
//创建运算符栈
void InitOptrStack(OPTR *optr)
{
optr->base=(char*)malloc(INIT_SIZE*sizeof(char));
if(optr->base==NULL)
exit(0);
optr->top=optr->base;
optr->stackSize=INIT_SIZE;
}
//输入表达式
void inputStr(char str[])
{
printf("请输入字符串表达式(输入#表示结束):\n");
gets(str);
}
//判断字符的类型
int getType(char ch)
{
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#')
return 1;
else
return 0;
}
char optr[7]={'+','-','*','/','(',')','#'};
char op[7][7]={
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=',' '},
{'>','>','>','>',' ','>','>'},
{'<','<','<','<','<',' ','='}
};
char compare(char op1,char op2)
{//op1为栈顶运算符,op2是扫描读到的运算符
int i=0,j=0;
while(optr[i]!=op1)
i++;
while(optr[j]!=op2)
j++;
return op[i][j];
}
//操作数入栈
void pushOprd(OPRD *oprd,double d)
{
if(oprd->top-oprd->base>=oprd->stackSize)
{
oprd->base=(double*)realloc(oprd->base,(oprd->stackSize+INCREMENT)*sizeof(double));
if(!oprd->base)
exit(0);
oprd->top=oprd->base+oprd->stackSize;
oprd->stackSize=oprd->stackSize+INCREMENT;
}
*(oprd->top)=d;
oprd->top++;
}
//运算符入栈
void pushOptr(OPTR *optr,char ch)
{
//栈满
if(optr->top-optr->base>=optr->stackSize)
{
optr->base=(char*)realloc(optr->base,(optr->stackSize+INCREMENT)*sizeof(char));
if(optr->base==NULL)
exit(0);
optr->top=optr->base+optr->stackSize;
optr->stackSize=optr->stackSize+INCREMENT;
}
*(optr->top)=ch;
optr->top++; //栈顶上移
}
//操作数出栈
void popOprd(OPRD *oprd,double *d)
{
if(oprd->top==oprd->base)
{
printf("空栈,操作数出栈错误!\n");
exit(0);
}
*d=*(--oprd->top);
}
//运算符出栈
void popOptr(OPTR *optr,char *ch)
{
if(optr->top==optr->base)
{
printf("空栈,运算符出栈错误!\n");
exit(0);
}
*ch=*(--optr->top);
}
//获取操作数栈顶元素
double getOprdTop(OPRD *oprd)
{
if(oprd->top==oprd->base)
{
printf("空栈,获取操作数栈顶元素失败!\n");
exit(0);
}
return *(oprd->top-1);//!!!
}
//获取运算符栈顶元素
char getOptrTop(OPTR *optr)
{
if(optr->top==optr->base)
{
printf("空栈,获取运算符栈顶元素失败!\n");
exit(0);
}
return *(optr->top-1);
}
//计算
double operate(double a,char op,double b)
{
switch(op)
{
case '+':
return a+b;
break;
case '-':
return a-b;
break;
case '*':
return a*b;
case '/':
return a*1.0/b;
break;
default:
printf("输入错误!\n");
}
}
//处理表达式
void fight(char ex[],OPRD *oprd,OPTR *optr)
{
double data,a,b;//a,b是表示弹出栈的操作数,data存储弹出来计算的结果
char op;//存储从栈顶取出的运算符
char charData[20];//存储字符型的数字
int i=0;//ops的索引
char *p=ex; //遍历表达式
printf("运算过程如下:\n");
while(*p!='#'||getOptrTop(optr)!='#')
{
if(getType(*p)==0)//不是运算符!
{
charData[i]=*p;//先存储到ops数组
p++;
++i;
if(getType(*p)==1)//下一个不是数字!
{
charData[i]='\0';
data=atof(charData);//atof把字符串变成浮点数
pushOprd(oprd,data);//把data入栈
i=0;//归零
}
}
else
{
switch(compare(getOptrTop(optr),*p))
{
case '<'://比栈顶运算符优先级高,新运算符压栈
pushOptr(optr,*p);
p++;
break;
case '='://脱括号
popOptr(optr,&op);
p++;
break;
case '>'://比栈顶运算符优先级低,运算!
popOptr(optr,&op);
popOprd(oprd,&a);
popOprd(oprd,&b);
pushOprd(oprd,operate(b,op,a));
printf("%.2lf%c%.2lf=%.2lf\n",b,op,a,operate(b,op,a));
break;
}
}
}
}
main()
{
//1,创建操作数栈和运算符栈
OPRD oprd;
OPTR optr;
InitOprdStack(&oprd);
InitOptrStack(&optr);
pushOptr(&optr,'#');//把#先压栈
//2,输入表达式
char ex[80];
inputStr(ex);
fight(ex,&oprd,&optr);
printf("\nresult=%.2lf",getOprdTop(&oprd)) ;
}
我是初学数据结构的小菜鸡,水平有限,查找了很多资料才得以理解,写第一篇博客,以此缅怀这段痛苦并收获的时光。
易错点:
1,栈顶指针,指向的是栈顶元素的上一个位置!
2,pop(OPRD *oprd,double *d);用指针的方法来接收出栈的值!如果用double d做参数,d的值不会改变!
难点:
1,比较运算符的优先级(解决:使用二维数组)
2,怎么让操作数和运算符入栈出栈:
遍历表达式字符串,只需要判断是否为运算符即可!!!
(1)当前扫描到的运算符优先级高于栈顶运算符,直接把新的运算符入栈
(2)当前扫描到的运算符优先级等于栈顶运算符,去括号
(3)当前扫描到的运算符优先级等于栈顶运算符,运算符栈顶元素出栈,操作数栈出栈两个操作数,进行运算,把运算结果再入操作数栈。
3,怎么提取到表达式字符串中的操作数:
如果该字符是数字,先存储到一个字符数组里并判断下一个字符是否为数字:
如果下一个字符是数字,继续遍历表达式字符串。
如果不是,使用atof(字符数组)函数,把字符串的数字转换为浮点数!
此方法解决了小数的问题!
运行结果如上图