下面利用栈实现了逆波兰计算器,将用户输入的中缀表达式转换为后缀表达式,再计算出结果。
使用了两个链栈,一个栈内的元素为字符型,用于处理用户输入的数据,将其转换为后缀表达式,储存在字符型数组中,再利用另一个栈,栈内元素为整型,利用栈处理后缀表达式再进行输出。
PS.只能进行整数运算,处理小数的话需要将处理后缀表达式的栈内的元素类型改为float或者double,而且需对小数点进行处理。
算法步骤:
step1:中缀表达式转换为后缀表达式
从头到尾读取中缀表达式中的每个对象:,对每个对象进行处理:
1.运算数:直接输出
2.左括号:入栈
3.右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
4.运算符:(优先级为:括号 > 乘除 > 加减)
若优先级大于栈顶运算符,则入栈
若优先级小于等于栈顶运算符,将栈顶运算符弹出并输出,再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后该运算符入栈(简单来说就是如果读取到加减号就一直pop到栈空或者pop出来是左括号,然后加减号入栈;如果读取到乘除符号,直接入栈)
5.对象处理完毕后,栈内运算符全部输出
step2:计算后缀表达式
1.从左到右遍历中缀表达式的每一个数字和符号
2.若是数字,则进栈
3.若是符号,则把处于栈顶的两个数字出栈,进行运算
4.运算结果进栈
5.直到获得最终结果并将最后结果出栈
代码如下:
#include
#include
#include
#include
#define DATASIZE 50//存放后缀表达式的数组长度
#define MAXBUFFER 10//最大缓冲区大小
typedef char ElemType;
typedef int elemtype;
typedef enum Status
{
error,
success
} Status;
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode, *LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
typedef struct stacknode
{
elemtype data;
struct stacknode *next;
}stacknode, *linkstackptr;
typedef struct linkstack
{
linkstackptr top;
int count;
}linkstack;
//函数的声明(链栈)
//栈内元素为字符型,用于处理输入的数据
Status initLStack(LinkStack *s);//初始化栈
Status notEmptyLStack(LinkStack *s);//判断栈是否为空
void Push(LinkStack *s,ElemType data);//入栈
void Pop(LinkStack *s,ElemType *data);//出栈
//栈内元素为整型,用于处理输出的数据
Status initlstack(linkstack *s);//初始化栈
void push(linkstack *s,elemtype data);//入栈
void pop(linkstack *s,elemtype *data);//出栈
//下面是字符型链栈基本操作的函数
Status initLStack(LinkStack *s)
{
s->top = NULL;
s->count = 0;
return success;
}
Status notEmptyLStack(LinkStack *s)
{
if(s->top != NULL)//非空返回1
{
return success;
}
else
{
return error;
}
}
void Push(LinkStack *s,ElemType data)
{
LinkStackPtr new = (LinkStackPtr)malloc(sizeof(StackNode));
if(new == NULL)
{
printf("内存分配失败\n");
system("pause");
exit(0);
}
new->data = data;
new->next = s->top;
s->top = new;
s->count++;
}
void Pop(LinkStack *s,ElemType *data)
{
if(s->top == NULL)
{
printf("栈空\n");
system("pause");
exit(0);
}
else
{
LinkStackPtr temp;
*data = s->top->data;
temp = s->top;
s->top = s->top->next;
free(temp);
s->count--;
}
}
//下面是整型链栈基本操作的函数
Status initlstack(linkstack *s)
{
s->top = NULL;
s->count = 0;
return success;
}
void push(linkstack *s,elemtype data)
{
linkstackptr new = (linkstackptr)malloc(sizeof(stacknode));
if(new == NULL)
{
printf("内存分配失败\n");
system("pause");
exit(0);
}
new->data = data;
new->next = s->top;
s->top = new;
s->count++;
}
void pop(linkstack *s,elemtype *data)
{
if(s->top == NULL)//栈空,对应错误:如用户输入:1+=
{
printf("\n出错:输入格式错误!\n");
printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
system("pause");
exit(0);
}
else
{
linkstackptr temp;
*data = s->top->data;
temp = s->top;
s->top = s->top->next;
free(temp);
s->count--;
}
}
int main(void)
{
//共用变量
int i = 0;//数组下标
//中缀表达式转换后缀表达式的变量
LinkStack s;
char c, d;//处理输入的数据
char data[DATASIZE];//存放后缀表达式
//计算后缀表达式的变量
linkstack s1;
char str[MAXBUFFER];//缓冲区,用于处理连续的数字
elemtype n1, n2;//处理输出的数据
int n = 0;//缓冲区内计数器
//初始化两个栈
if(!initLStack(&s))
{
printf("初始化失败\n");
system("pause");
return -1;
}
if(!initlstack(&s1))
{
printf("初始化失败\n");
system("pause");
return -1;
}
//下面将中缀表达式转换为后缀表达式储存在数组data中
printf("请输入中缀表达式,以=作为结束标志(只能进行整数运算):");
scanf("%c", &c);
while( c != '=' )//一直接收用户输入,直到读取到=为止
{
while(c>='0' && c<='9')//整数直接存入数组
{
data[i] = c;
i++;
scanf("%c", &c);
if(c<'0' || c>'9')//处理连续的数字
{
data[i] = ' ';
i++;
}
}
if(c == ')')
{
Pop(&s, &d);//出栈
while(d != '(')//不是左括号就存入数组
{
data[i] = d;
i++;
Pop(&s, &d);
}
}
else if(c == '+' || c == '-')
{
if(!notEmptyLStack(&s))//栈空即入栈
{
Push(&s, c);
}
else//栈非空则比较栈顶元素
{
do
{
Pop(&s, &d);
if(d == '(')
{
Push(&s, d);
}
else//不是左括号就存入数组
{
data[i] = d;
i++;
}
}while(notEmptyLStack(&s) && d != '(');
//直到栈空或者读取到左括号
Push(&s, c);//然后再入栈
}
}
else if(c == '(' || c == '*' || c == '/')
{
Push(&s, c);
}
else if(c == '=')
{
break;
}
else
{
printf("\n出错:输入格式错误!\n");
printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
system("pause");
return -1;
}
scanf("%c", &c);
}
//检查如果=前无运算符,eg:1=
if(!notEmptyLStack(&s))
{
printf("\n出错:输入格式错误!\n");
printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
system("pause");
return -1;
}
while(notEmptyLStack(&s))//将栈内剩余对象存放到数组
{
Pop(&s, &data[i]);
i++;
data[i] = '=';
data[i+1] = '\0';//字符串结束标志
}
printf("\n后缀表达式:\n");
printf("%s\n", data);
//下面计算后缀表达式
for(i = 0; data[i] != '\0'; i++)
{
//下面对数字进行处理
while(isdigit(data[i]))
{
str[n++] = data[i++];
str[n] = '\0';//字符串结束
if(n >= MAXBUFFER)
{
printf("输入的单个数据过大\n");
system("pause");
return -1;
}
if(data[i] == ' ')//读取到空格时对前面的所有数字进行处理
{
n1 = atoi(str);//将字符串转换成整型数据
push(&s1, n1);
n = 0;//计数器重新初始化
break;
}
}
switch(data[i])//过滤掉数字后对剩下的符号进行选择
{
case '+':
{
pop(&s1, &n1);
pop(&s1, &n2);
push(&s1, n1 + n2);
break;
}
case '-':
{
pop(&s1, &n1);
pop(&s1, &n2);
push(&s1, n2 - n1);
break;
}
case '*':
{
pop(&s1, &n1);
pop(&s1, &n2);
push(&s1, n1 * n2);
break;
}
case '/':
{
pop(&s1, &n1);
pop(&s1, &n2);
if(n1 != 0)
push(&s1, n2 / n1);
else
{
printf("\n出错:除数不能为零\n");
system("pause");
return -1;
}
break;
}
}
}
pop(&s1, &n1);
printf("\n计算结果为:%d\n\n", n1);
system("pause");
return 0;
}