因为数据结构老师布置了栈的后缀表达式实验,经过思考,有以下反思。
中缀表达式转换为后缀表达式
- 关于括号,直接将括号里面的符号加入后缀表达式。
- 关于数字,直接推入后缀表达式
- 遇到±符号,如果栈为空或者栈顶为“(”,直接将符号推入栈,如果栈不为空,且栈顶不为“(”,则推出栈顶符号。再将±符号推入符号栈。
- 如果遇到“/”符号,如果如果栈为空或者栈顶为“(”,直接推入栈,如果栈不为空,且栈顶符号优先级大于或者等于“/”符号,则推出栈顶符号。再将*/符号推入符号栈。
- 如果最后符号栈还有符号,直接加入后缀表达式。
实际上也就是优先级比较的问题。
后缀表达式的计算:
后缀表达式的计算,只需要从左到右,遇到运算符就计算即可,无需考虑优先级的问题
代码块如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node{
int data;
struct node *next;
}node,*link;
typedef struct snode
{
char c;
struct snode *next;
}snode,*slink;
void dealExpression();
char opTop(slink &s);
void push(link &s,int x);
void push1(slink &s,char x);
int pop1(slink &s);
int pop(link &s);
void calculate(link &s,slink &s1);
int main(void)
{
dealExpression();
}
void empty(link &s)
{
s=NULL;
}
void empty1(slink &s)
{
s=NULL;
}
void push(link &s,int x)
{ node *p=(link )malloc(sizeof(node));
p->data=x;
p->next=s;
s=p;
}
void push1(slink &s,char x)
{ snode *p=(slink )malloc(sizeof(snode));
p->c=x;
p->next=s;
s=p;
}
int pop(link &s)
{
int x;
if(s==NULL){
printf("it is an empty stack");
}
else{
x=s->data;
s=s->next;
return x;
}
}
int pop1(slink &s)
{
snode *p=s;
char x;
if(s==NULL){
printf("it is an empty stack");
}
else{
x=p->c;
s=s->next;
free(p);
return x;
}
}
char opTop(slink &s1){
if(s1==NULL){
return 0;
}
else{
return s1->c;
}
}
//计算,将栈中的数值和运算符进行计算
void calculate(link &s,slink &s1)
{
int number1,number2;
char opf;
number1=pop(s);
number2=pop(s);
opf=pop1(s1);
int tmpResult=0;
switch(opf){
case '+':
tmpResult=number1+number2;
break;
case '-':
tmpResult=number2-number1;
break;
case '*':
tmpResult=number2*number1;
break;
case '/':
tmpResult=number2/number1;
break;
}
push(s,tmpResult);
}
//将中缀表达式转化为后缀,并且存储在数值中
void dealExpression()
{
char change[100];
int i=0;
char a,b;
node *s;
snode *s1;
//定义节点一定要初始化节点,要不然会发生分配内存错误
empty(s);
empty1(s1);
char currentchar;
scanf("%c",¤tchar);
// 转换过程
while(currentchar!='='){
switch(currentchar){
case '+':
case '-':
if(opTop(s1)==0){
push1(s1,currentchar);
}
else{
while(opTop(s1)=='+'||opTop(s1)=='-'||opTop(s1)=='*'||opTop(s1)=='/')
{
a=pop1(s1);
change[i]=a;
i++;
printf("%c",a);
}
push1(s1,currentchar);
}
scanf("%c",¤tchar);
break;
case '*':
case '/':
if(opTop(s1)==NULL){
push1(s1,currentchar);
}
else{
while(opTop(s1)=='*'||opTop(s1)=='/')
{
a=pop1(s1);
change[i]=a;
i++;
printf("%c",a);
}
push1(s1,currentchar);
}
scanf("%c",¤tchar);
break;
case '(':
push1(s1,currentchar);
scanf("%c",¤tchar);
break;
case ')':
while(opTop(s1)!='('){
b=pop1(s1);
change[i]=b;
i++;
printf("%c",b);
}
pop1(s1);
scanf("%c",¤tchar);
break;
default:
int opNum=0;
while(currentchar>='0'¤tchar<='9'){
// 通过递归实现二位到以上的数
opNum=opNum*10+currentchar-'0';
scanf("%c",¤tchar);
}
change[i]=char(opNum);
i++;
printf("%d",opNum);
break;
}
}
while(opTop(s1)!=0)
{
a=pop1(s1);
change[i]=char(a);
i++;
printf("%c",a);
}
// 将转化的后缀表达式进行计算,如果遇到操作符,直接计算就可,无需考虑优先级,只需要考虑到从左至右的顺序
int j=0;
while(j<i){
switch(change[j]){
case '+':
case '-':
case '*':
case '/':
push1(s1,change[j]);
calculate(s,s1);
// 重要,因为break语句导致我调试了很久
break;
default:
push(s,int(change[j]));
}
j++;
}
while(opTop(s1)!=0){
calculate(s,s1);
}
int result;
result=pop(s);
printf("\n%d",result);
}
遇到的问题和反思:
解决了上次中缀表达式中,地址分配错误的问题,因为上次中缀表达式,我没有将栈初始化,所以导致了地址分配错误,所以将栈初始化是很重要的。
然后遇到了case,break的问题,我大意忘记写了break,结果导致了我调试了很久才发现问题:问题是这样的,我输入的 1+2= 结果却是45,在调试中发现“+”的ASCLL码正好是43,而且在最后一次case循环中,不仅是符号栈有输入,数字栈也有输入。才发现是忘记写break,导致最后一次循环:符号栈和数字栈都有输入,符号栈的输入是“+”,数字栈的输入是“43”.所以导致最后结果是45.