中缀计算器(先中缀转后缀,再RPN计算)
关于代码想说的:
1.有人会问为什么要做两个栈 解决:因为在中缀转后缀中第一个栈被销毁的
2.缓冲量的作用 解决:接收空格
3.如何结合中缀转后缀和RPN计算 解决:将中缀转后追的输出放进数组string中,然后在RPN计算中本来要输入的直接在数组里拿就好,注意不要忘记空格
/*************************************************************************
> File Name: 中缀计算器.c
> Author: geeker
> Mail: 932834897@qq.com
> Created Time: 2017年02月08日 星期三 15时32分41秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#include <ctype.h>
#define stacksize 20//栈的最大容量
#define maxbuffer 10//缓冲量
char string[50];//定义一个字符数组,将中缀转后缀的输出数据放到数组中,再取数组元素进行逆波兰计算
typedef char ElemType;//19-25行是给中缀转后缀用的
typedef struct
{
ElemType *base;
ElemType *top;
int maxsize;
}sqStack;
typedef double bElemType;//28-33行是给逆波兰计算用的
typedef struct
{
bElemType *base;
bElemType *top;
int maxsize;
}bsqStack;
void InitStack(sqStack *s)//初始化
{
s->base=(ElemType *)malloc(stacksize * sizeof(ElemType));
if(!s->base)//分配失败退出程序
{
exit(0);
}
s->top=s->base;
s->maxsize=stacksize;
}
void Push(sqStack *s,ElemType e)//压栈
{
if(s->top-s->base>=s->maxsize)
{
return;
}
*(s->top)=e;//给当前栈顶赋值
s->top++;//栈顶元素加1
}
void Pop(sqStack *s,ElemType *e)//出栈
{
if(s->top==s->base)
{
return;
}
*e=*--(s->top);
}
int StackLen(sqStack s)//计算容量
{
return(s.top-s.base);
}
void bInitStack(bsqStack *s)//再次初始化(为什么要再次初始化、压栈等等,因为在中转后的change函数中已经把栈给销毁了,所以要重新建立)
{
s->base=(bElemType *)malloc(stacksize * sizeof(bElemType));
if(!s->base)
{
exit(0);
}
s->top=s->base;
s->maxsize=stacksize;
}
void bPush(bsqStack *s,bElemType e)//再次压栈
{
if(s->top-s->base>=s->maxsize)
{
return;
}
*(s->top)=e;
s->top++;
}
void bPop(bsqStack *s,bElemType *e)//再次出栈
{
if(s->top==s->base)
{
return;
}
*e=*--(s->top);
}
int bStackLen(bsqStack s)//再次求栈容量
{
return(s.top-s.base);
}
void DestroyStack(sqStack *s)//销毁栈
{
free(s->base);
s->base=s->top=NULL;
s->maxsize=0;
}
void DestroyBStack(bsqStack *s)//再次销毁栈
{
free(s->base);
s->base=s->top=NULL;
s->maxsize=0;
}
int change()//就是中缀转后缀的一个函数,然而区别就在于将输出的数据存入到string数组中,所以每一次printf就会跟string[i++];
{
sqStack s;
char c,e;
InitStack(&s);
int i=0;
printf("请输入中缀表达式,以#为结束标志\n");
scanf("%c",&c);
while(c!='#')
{
while(c>='0'&&c<='9')
{
printf("%c",c);
string[i++]=c;//关键。。把输出的数据放到数组中
scanf("%c",&c);
if(c<'0'||c>'9')
{
printf(" ");
string[i++]=' ';
}
}
if(')'==c)
{
Pop(&s,&e);
while('('!=e){
printf("%c ",e);
string[i++]=e;
string[i++]=' ';
Pop(&s,&e);
}
}
else if('+'==c||'-'==c)
{
if(!StackLen(s))
{
Push(&s,c);
}
else
{
do
{
Pop(&s,&e);
if('('==e)
{
Push(&s,e);
}
else
{
printf("%c",e);
string[i++]=e;
}
}while(StackLen(s)&&'('!=e);
Push(&s,c);
}
}
else if('*'==c||'/'==c||'('==c)
{
Push(&s,c);
}
else if('#'==c)
{
break;
}
else
{
printf("\n出错,程序输入错误\n");
return -1;
}
scanf("%c",&c);
}
while(StackLen(s))
{
Pop(&s,&e);
printf("%c ",e);
string[i++]=e;
string[i++]=' ';
}
printf("\n");
string[i]='\0';
printf("%s\n",string);
string[i]='#';//这里特别重要,很容易忘记,忘记了很难找到错误,切记!
DestroyStack(&s);
return 0;
}
int main()//这个main函数其实就是一个逆波兰计算器,区别就是将数组中的数据当做本来要输入的字符,即char *p=string;c=*p++;然后c就是那个看做输入的字符,逆波兰在前面的博客已经有算法,不多解释
{
bsqStack s;
char c;
double d,e;
char str[maxbuffer];//缓冲
int f=0;
change();
bInitStack(&s);
printf("请按逆波兰表达式输入带计算数据,数据与运算符之间用空格隔开,以#作为结束标志\n");
char *p=string;//关键
c=*p++;
while(c!='#')
{
while(isdigit(c)||c=='.')
{
str[f++]=c;
str[f]='\0';
if(f>=10)
{
printf("error,输入单个数据过大\n");
return -1;
}//缓冲区最大范围
// scanf("%c",&c)
c=*p++;//这里本来是输入的,但所有数据已存在数组中
if(c==' ')
{
d=atof(str);//功能
bPush(&s,d);
f=0;
break;
}
}
switch(c)
{
case'+':
bPop(&s,&e);
bPop(&s,&d);
bPush(&s,d+e);
break;
case'-':
bPop(&s,&e);
bPop(&s,&d);
bPush(&s,d-e);
break;
case'*':
bPop(&s,&e);
bPop(&s,&d);
bPush(&s,d*e);
break;
case'/':
bPop(&s,&e);
bPop(&s,&d);
if(e!=0)
{
bPush(&s,d/e);
}
else
{
printf("\nerror,除数不能为0\n");
return -1;
}
break;
}
// scanf("%c",&c);
c=*p++;
}
bPop(&s,&d);
printf("\n最终计算结果为: %lf\n",d);
DestroyBStack(&s);//别忘记销毁栈
return 0;
}