逆波兰计算器的C语言实现
这个函数完成的功能:输入一个中缀表达式(支持负数和小数),输出相应的计算结果
例如:输入(1+3)*4+5.2/2#, 输出结果18.600000
(#代表表达式结束)
主要使用栈来实现操作。第一步将输入的中缀表达式转换为后缀表达式,存储在字符数组中;第二部计算后缀表达式
下面是代码,不足之处还望大佬指出
修改之后可以支持负数和小数的计算
// code
//逆波兰计算器
//支持负数和小数计算
#include <stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
#define buffer_size 10 //缓存数字串的大小
#define STORESIZE 100 //存储后缀表达式的字符数组长度 如果过小需要手动扩容
typedef char ElemTypec; //栈1元素为字符
typedef double ElemTyped; //栈2元素为浮点数
typedef struct
{
ElemTypec *base;
ElemTypec *top;
int stack_size;
}sqStack1; //栈1用来将中缀表达式转换为后缀表达式
typedef struct
{
ElemTyped *base;
ElemTyped *top;
int stack_size;
}sqStack2; //栈2用来计算后缀表达式
//初始化
void InitStack1(sqStack1 *s)
{
s->base = (ElemTypec *)malloc(STACK_INIT_SIZE*sizeof(ElemTypec));
if( !s->base)
{
exit(0);
}
s->top = s->base;
s->stack_size = STACK_INIT_SIZE;
}
void InitStack2(sqStack2 *s)
{
s->base = (ElemTyped *)malloc(STACK_INIT_SIZE*sizeof(ElemTyped));
if( !s->base)
{
exit(0);
}
s->top = s->base;
s->stack_size = STACK_INIT_SIZE;
}
//入栈
void Push1(sqStack1 *s, ElemTypec e)
{
//自动扩容
if(s->top - s->base >= s->stack_size)
{
s->base = (ElemTypec *)realloc(s->base, (s->stack_size + STACKINCREMENT)*sizeof(ElemTypec));
if( !s->base)
{
exit(0);
}
s->top = s->base + s->stack_size;
s->stack_size = s->stack_size + STACKINCREMENT;
}
*(s->top) = e;
s->top++;
}
void Push2(sqStack2 *s, ElemTyped e)
{
if(s->top - s->base >= s->stack_size)
{
s->base = (ElemTyped *)realloc(s->base, (s->stack_size + STACKINCREMENT)*sizeof(ElemTyped));
if( !s->base)
{
exit(0);
}
s->top = s->base + s->stack_size;
s->stack_size = s->stack_size + STACKINCREMENT;
}
*(s->top) = e;
s->top++;
}
//出栈
void Pop1(sqStack1 *s, ElemTypec *e)
{
if(s->top == s->base)
{
exit(0);
}
*e = *--(s->top);
}
void Pop2(sqStack2 *s, ElemTyped *e)
{
if(s->top == s->base)
{
exit(0);
}
*e = *--(s->top);
}
//检查长度
long STACKLENGTH(sqStack1 s)
{
return (s.top - s.base);
}
//存入后缀表达式的结果
void SaveChar(char *array, int *count, char c)
{
array[*count] = c;
(*count)++;
}
//获取后缀表达式用于计算
char GetChar(char *array, int *count)
{
char c;
c = array[*count];
(*count)++;
return c;
}
int main()
{
//中缀表达式变为后缀表达式
sqStack1 s;
char c, e;
int count = 0, flag = 0, minus_flag = 0;
char string_store[STORESIZE];
InitStack1(&s);
printf("请输入中缀表达式,以#结束\n");
printf("例如:(1+3)*4+5.2/2#\n");
scanf("%c", &c);
if(c == '-') //第一个数为负数
{
SaveChar(string_store, &count, c);
minus_flag = 1;
}
while(c != '#')
{
if(flag && c != '-') //左括号下一个不是-号,把flag置0
{
flag = 0;
}
while((c >= '0' && c <= '9') || c == '.')
{
SaveChar(string_store, &count, c);
scanf("%c", &c);
if( !((c >= '0' && c <= '9') || c == '.'))
{
SaveChar(string_store, &count, ' ');
break;
}
}
if(c == ')')
{
Pop1(&s, &e);
while(e != '(')
{
SaveChar(string_store, &count, e);
SaveChar(string_store, &count, ' ');
Pop1(&s, &e);
}
}
else if(c == '+')
{
if(!STACKLENGTH(s))
{
Push1(&s, c);
}
else
{
do
{
Pop1(&s, &e);
if(e == '(' )
{
Push1(&s ,e);
}
else
{
SaveChar(string_store, &count, e);
SaveChar(string_store, &count, ' ');
}
}while(STACKLENGTH(s) && e != '(');
Push1(&s, c);
}
}
else if(c == '-')
{
if(minus_flag && flag == 0)
{
scanf("%c", &c); //输入开头为负数,跳到下一次循环
minus_flag = 0;
continue;
}
if(!STACKLENGTH(s) && minus_flag == 0 && flag == 0) //栈为空且开头没有负号,说明是减号,把减号入栈
{
Push1(&s, c);
}
else
{
//如果前一个字符是(,那么下一个字符为-则必为负号
if(flag)
{
SaveChar(string_store, &count, '-');
}
do
{
Pop1(&s, &e);
if(e == '(' )
{
Push1(&s ,e);
}
else
{
SaveChar(string_store, &count, e);
SaveChar(string_store, &count, ' ');
}
}while(STACKLENGTH(s) && e != '(');
if(flag == 0)
{
Push1(&s, c);
}
else
{
flag = 0;
}
}
}
else if('*' == c || '/' == c)
{
if(!STACKLENGTH(s))
{
Push1(&s, c);
}
else
{
Pop1(&s, &e);
if(e == '+' || e == '-')
{
Push1(&s, e);
Push1(&s, c);
}
else if(e == '*' || e == '/')
{
SaveChar(string_store, &count, e);
SaveChar(string_store, &count, ' ');
Push1(&s, c);
}
else if(e == '(')
{
Push1(&s, e);
Push1(&s, c);
}
}
}
else if(c == '(')
{
Push1(&s, c);
flag = 1;
}
else if(c == '#')
{
break;
}
else
{
printf("输入有误\n");
}
scanf("%c", &c);
};
while(STACKLENGTH(s))
{
Pop1(&s, &e);
SaveChar(string_store, &count, e);
SaveChar(string_store, &count, ' ');
}
getchar();
printf("\n");
string_store[count] = '\0';
printf("逆波兰表达式:%s\ncount:%d\n", string_store, count);
//把后缀表达式计算出来
sqStack2 s2;
int i = 0;
flag = 0;
double sum1, sum2, temp;
char buffer[buffer_size];
char detect;
InitStack2(&s2);
count = 0;//count从头遍历
c = GetChar(string_store, &count);
while( c != '\0' )
{
//数字则入栈
while(isdigit(c) || c == '.')
{
buffer[i++] = c;
buffer[i] = '\0';
if(i >= buffer_size-1)
{
printf("输入数据过大\n");
return -1;
}
c = GetChar(string_store, &count);
if( c == ' ')
{
temp = atof(buffer); //字符转换为数字
if(flag)
{
temp = -temp; //如果是负数
flag = 0;
}
Push2(&s2, temp);
i = 0;
break;
}
}
//遇到操作符就运算
switch ( c )
{
case ' ':
break;
case '+':
Pop2(&s2, &sum1);
Pop2(&s2, &sum2);
Push2(&s2, sum1 + sum2);
break;
case '-':
//读取到字符‘-’, 要检测是负号还是减号
detect = GetChar(string_store, &count);
if(detect == ' ') //下一个字符为空,则是减号 正常操作进行弹栈
{
count--;
Pop2(&s2, &sum1);
Pop2(&s2, &sum2);
Push2(&s2, sum2 - sum1);
}
else if (isdigit(detect)) //下一个字符为数字,则是负号
{
count--;
flag = 1;
}
break;
case '*':
Pop2(&s2, &sum1);
Pop2(&s2, &sum2);
Push2(&s2, sum1 * sum2);
break;
case '/':
Pop2(&s2, &sum1);
Pop2(&s2, &sum2);
if(sum1 != .0)
{
Push2(&s2, sum2 / sum1);
}
else
{
printf("除数为0,错误");
return -1;
}
break;
default:
printf("非四则运算\n");
return -1;
}
c = GetChar(string_store, &count);
}
Pop2(&s2, &sum1);
printf("输出计算结果:%f\n", sum1);
return 0;
}
下面是测试用例:
输入:3+2.5*2#
输出:8.000000 正确
输入:-3*2+5-2/8+(-2+5)*3+2#
输出:9.750000 正确
输入:-1.52.8+(-2.5-4)/23#
输出:-13.950000 正确
输入:-2.12*23+(-5.212+2.3)*3+((-2.1+3)*2+5)*1.1#
输出:-50.016 正确
输入:-2.12*23+(-5.212+2.3)*3+(-2.1+3)*2+5#
输出:-50.696000 正确
输入:-2.12245+(((23+1.1)+4.1)*2.4-(-1.1+3)/2)*2.1#
输出:-464.947000 正确
通过测试过程修正了代码,如果遇到了不正确的输出可以与我交流