《資料結構和演算法》之中綴表示式、字尾表示式轉換
一,在上篇博文中討論了逆波蘭表示式的計算問題,在這裡討論一下中綴表示式如何轉換為字尾表示式
問題示例:如何將1+(2-3)*4+10/5 轉換為字尾表示式 1 2 3 - 4 * + 10 5 / +這樣的輸出
問題分析:
第一步,首先遇到第一個輸入是數字1,數字在後綴表示式中都是直接輸出,接著是符號“+”入棧
第二步,第三個字元是“(”,依然是符號,這個時候將此符號入棧,接著是數字2,直接輸出,然後是符號“-”,這個時候符號仍然入棧
第三步,接下來是數字3,輸出,緊跟著是“)”,此時,我們需要匹配棧裡的“(”,然後再匹配前將棧頂資料依次出棧:
第四步,緊接著是符號“*”,直接入棧:
第五步,遇到數字4,直接輸出,之後是符號“+”,此時棧頂元素是符號“*”,按照先乘除後加減原理,此時棧頂的乘號優先順序比即將入棧的加號要大,所以出棧。而棧中的第二個元素是加號,按照先到先後的原則,這個時候“+”也要出棧。
第六步,緊接著是數字10,直接輸出,最後是符號“/”,進棧:
第七步,最後一個數字5,這個時候直接輸出5,但是棧裡仍然有資料,此時可以將棧中符號依次出棧。
二,程式碼分析:
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #define STACK_INIT_SIZE 20 #define STACKINCREMENT 10 #define MAXBUFFER 10 typedef char ElemType; typedef struct { ElemType *base; ElemType *top; int stackSize; }sqStack; void InitStack(sqStack *s) { s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType)); if( !s->base ) exit(0); s->top = s->base; s->stackSize = STACK_INIT_SIZE; } void Push(sqStack *s, ElemType e) { //如果棧滿一定要增加空間,所以在之前要做一個判斷 if( s->top - s->base >= s->stackSize) { s->base = (ElemType *)realloc(s->base, (s->stackSize + STACKINCREMENT)* sizeof(ElemType)); if(!s->base) exit(0); s->top = s->base + s->stackSize; s->stackSize = s->stackSize + STACKINCREMENT; } *(s->top) = e; s->top++; } void Pop(sqStack *s, ElemType *e) { if( s->top == s->base) return; *e = *--(s->top); //將棧頂元素彈出並修改棧頂指標 } int StackLen(sqStack s) { return (s.top - s.base); } int main() { sqStack s; ElemType c,e; InitStack( &s ); printf("請輸入中綴表示式,以#為結束標誌:"); scanf("%c", &c); while( c != '#') { if( c >= '0' && c <= '9') { printf("%c", c); } else if( ')' == c ) { Pop(&s, &e); while('(' != e) { printf("%c", e); 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); } }while( StackLen(s) && '(' != e); Push(&s, c); } } else if( '*' == c || '/' == c || '(' == c) { Push(&s, c); } else { printf("輸入錯誤,請重新輸入!\n"); return -1; } scanf("%c", &c); } while( StackLen(s)) { Pop( &s, &e); printf("%c", e); } return 0; }
最後的結果
大家可以看到這樣的結果直接連在一起了,很難分辨出來是123還是1 2 3,這個時候就要在輸出做一個改動,將printf("%c"改為printf("%c ",加了一個空格,但是出現了這樣的結果:
這樣可以看到10被拆分成了1 0,顯然這樣是不合理的。此時再修改程式,將主函式main修改如下:
int main()
{
sqStack s;
ElemType c,e;
InitStack( &s );
printf("請輸入中綴表示式,以#為結束標誌:");
scanf("%c", &c);
while( c != '#')
{
while( c >= '0' && c <= '9')
{
printf("%c", c);
scanf("%c",&c);
if( c<'0' || c>'9')
{
printf(" ");
}
}
if( ')' == c )
{
Pop(&s, &e);
while('(' != e)
{
printf("%c ", e);
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);
}
}while( StackLen(s) && '(' != e);
Push(&s, c);
}
}
else if( '*' == c || '/' == c || '(' == c)
{
Push(&s, c);
}
else if( '#' == c)
{
break;
}
else
{
printf("輸入錯誤,請重新輸入!\n");
return -1;
}
scanf("%c", &c);
}
while( StackLen(s))
{
Pop( &s, &e);
printf("%c ", e);
}
return 0;
}
最終得出想要的滿意結果: