1. 程式人生 > >《資料結構和演算法》之中綴表示式、字尾表示式轉換

《資料結構和演算法》之中綴表示式、字尾表示式轉換

一,在上篇博文中討論了逆波蘭表示式的計算問題,在這裡討論一下中綴表示式如何轉換為字尾表示式

       問題示例:如何將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;
}

             最終得出想要的滿意結果: