这是用堆栈的方式建立中缀表达式转后缀表达式的代码,这个代码我打了很久,一开始是在优酷上通过一个视频有关的思路讲解打出来的。
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define MAXSIZE 20
#define STACKINCREMENT 10
typedef struct SNode *PtrToSNode;
struct SNode
{
char *date;
int Top;
int Base;
int MaxSize;
};
typedef PtrToSNode Stack;
Stack CreatStack(int MaxSize)
{
Stack S = (Stack)malloc(sizeof(struct SNode));
S->date = (char *)malloc(MaxSize*sizeof(char));
S->Top = S->Base;
S->MaxSize = MaxSize;
return S;
}
void Push( Stack S, char X )
{
//增加内存
if( S->Top - S->Base >= S->MaxSize )
{
S->date = (char *)realloc(S->date, (S->MaxSize + STACKINCREMENT )*sizeof(char));
if(!S->date)
exit(0);
S->Top = S->Base + S->MaxSize;
S->MaxSize = S->MaxSize + STACKINCREMENT;
}
S->date[(S->Top)++] = X;
// printf("\nS->Top=%d 符号为:%c\n",S->Top-1, S->date[S->Top-1] );
}
int StackLen(Stack S)
{
return (S->Top-S->Base);
}
char Pop(Stack S)
{
if( S->Top == S->Base )
return 0;
// printf("\n出来时 S->Top=%d 符号位:%c\n", S->Top-1, S->date[S->Top-1]);
return (S->date[--S->Top]);
}
int main()
{
Stack S;
char c, k;
S = CreatStack(MAXSIZE);
printf("输入中缀表达式:");
scanf("%c", &c);
printf("后缀表达式为:");
while( c!='\n' )
{
while( c>='0' && c<='9' )
{
printf("%c", c);
scanf("%c", &c);
if( c<'0'||c>'9')
printf(" ");
}
if( ')' == c )
{
k = Pop(S);
while( '(' != k )
{
printf("%c ", k);
k = Pop(S);
}
}
else if( '+' == c || '-' == c )
{
if(!StackLen(S))
Push(S, c);
else
{
do
{
k = Pop(S);
if( '(' == k )
{
Push(S, k);//-->在这里不能用c,要用k重新将'('符号收回栈中
}
else
{
printf("%c ", k);
}
}while( StackLen(S) && '(' != k );
Push(S, c);
}
}
else if( '*'==c || '/'==c || '('==c)
{
Push(S, c);
}
else if('\n' == c)
break;
else
{
printf("\n输入错误: 输入格式错误!\n");
return -1;
}
scanf("%c", &c);
}
while(StackLen(S))
{
k = Pop(S);
printf("%c ", k);
}
return 0;
}
//1+2*(2+3)-8/2
那就在这里详细说说中缀表达式转后缀表达式的具体思路:
1)第一次先遇见 ‘1’,直接输出,接着遇见符号‘+’,直接压入栈中:
2)第二次遇到数字‘2’的时候直接输出,输出后遇到‘ * ’符号,再次压入栈中,如下图:
3)在第二步后,后面的步骤也是相同的,但我们并不是一直把所有符号都收入栈中,如果有开括号,就要再一直压入栈中,直到遇到收括号,这时不必将收括号压入栈中,把括号中的符号和开括号前面的符号全部弹出了,入下图:
4)需要注意的是括号要避开输出,而这段代码里面可能有人不一定理解 if(‘+’||‘-’)这个条件里面的代码:
else if( '+' == c || '-' == c )
{
if(!StackLen(S))//当栈中为空的时候将遇到的加减符号直接压入栈中
Push(S, c);
else
{
do
{
k = Pop(S);
if( '(' == k )
{
Push(S, k); //-->在这里不能用c,要用k重新将'('符号收回栈中 ,好吧,这里也是我自己打错的地方,找了好久
}
else
{
printf("%c ", k);
}
}while( StackLen(S) && '(' != k );
Push(S, c);
}
}
上面的do{}while();循环可能理解上有些难,不过解释前先强调一下,你要明白后缀表达式的输出规则是什么,当遇到括号里面有大量的加减乘除,例如2*(2+3+4+5+6+7-8-9)/2 ,输出为:2 2 3 + 4 + 5 + 6 + 7 + 8 - 9 - 2 / *,要注意到括号里面的t弹出为首先是2 3 +,在这之后的弹出为4 +,4后面弹出的‘+’号是4前面的符号,也就是说,当栈中连续第二次碰到加减符号,就必须要把前面的‘+’或‘-’符号弹出,于是在第一次弹出‘+’或‘-’符号后,在括号前停止输出,便有条件:while( StackLen(S) && '(' != k ); 同时我们用的是do while循环,他会先执行,后判断条件,这样一来就会导致‘(’开括号符号被弹出,于是便有 if( '(' == k )Push(S, k); 为的是将被弹出的‘(’开括号符号重新压入栈中,你可能想说直接用while()不好么,emmmmmmm, 你可以用我的代码直接试一下就明白了,你不还得判断有没有遇到‘(’开括号吗?那怎么遇到的?不就是将它弹出吗。。。而且弹出后不还得接着把它压回去, 而在while语句执行完毕后,就要把一开始遇到的符号压入栈中,便有 Push(S, c); 所以解释道这里,应该能明白这段代码的意思了吧。
最后就是必须要提醒的是,当我们把括号中所有的符号输出后,还会有括号前面的符号压在栈中,于是我们在括号后就要一口气弹出所有的剩余符号,于是就有下面的代码:
while(StackLen(S))
{
k = Pop(S);
printf("%c ", k);
}
那么到了这里,这段代码的解释就全部结束了。
编译器用DEV C++