1. 程式人生 > >棧在表示式計算過程中的應用【轉】

棧在表示式計算過程中的應用【轉】

棧在表示式計算過程中的應用 :建立運算元棧和運算子棧。運算子有優先順序。 
規則: 
自左至右掃描表示式,凡是遇到運算元一律進運算元棧。 

當遇到運算子時,如果它的優先順序比運算子棧棧頂元素的優先順序高就進棧。反之,取出棧頂運算子和運算元棧棧頂的連續兩個運算元進行運算,並將結果存入運算元棧,然後繼續比較該運算子與棧頂運算子的優先順序。 

左括號一律進運算子棧,右括號一律不進運算子棧,取出運算子棧頂運算子和運算元棧頂的兩個運算元進行運算,並將結果壓入運算元棧,直到取出左括號為止。
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX  100

enum link{PUSH, PUSH_NO};

typedef struct      // 運算數
{
    int num[MAX];
    int top;
}OP_num;

typedef struct      // 運算子
{
    char str[MAX];
    int top;
}OP_ch;

// 運算數置空棧
void SETNULL_num (OP_num* s)        
{
    s->top = -1;
}

// 運算子置空棧
void SETNULL_ch (OP_ch* s)
{
    s->top = -1;
}

// 判斷是否是數字,是返回1 不是返回0
int is_num (char ch)    
{
    if (ch >= '0' && ch <= '9')
    {
        return 1;
    }
    else
    {
        return 0;
    }
}       

// 數字入棧
int PUSH_num (OP_num *s, int data)
{
    if ((MAX - 1) == s->top)
    {
        return 0;
    }
    else
    {   
        s->num[++s->top] = data;
    }
}

// 運算子入棧
int PUSH_ch (OP_ch* s, char ch)
{
    if ((MAX - 1) == s->top)
    {
        return 0;
    }
    else
    {
        s->str[++s->top] = ch;
    }
}

// 判斷是否將運算子入棧
int jud (OP_ch* s, char ch)
{
    if (-1 == s->top)   // 判斷是否是空棧
    {
        return PUSH;
    }
    else
    {
        switch (s->str[s->top])     // 根據棧頂運算判斷是否進棧
        {
            case '+':           //  當棧頂是'+-'時,只有‘+-)’不進棧
            case '-':
            {
                if (ch == '+' || ch == '-' || ch == ')')
                {
                    return PUSH_NO;
                }
                else
                {
                    return PUSH;
                }
                break;
            }
            case '*':
            case '/':
            {
                if ('(' == ch)
                {
                    return PUSH;
                }
                else
                {
                    return PUSH_NO;
                }
                break;
            }
            case '(':
            {
                return PUSH;
                break;
            }
        }
    }
}


// 數字出棧
int Pop_num (OP_num* s)
{
    return (s->num[s->top--]);
}

// 運算子出棧
void Pop_ch (OP_ch* s)
{
    s->top--;
}

// 進行運算
void operate (OP_ch* s_ch, OP_num* s_sum)
{
    int a = Pop_num(s_sum);                     // 取第一個數
    int b = Pop_num(s_sum);                     // 取第二個數
    int result;

    // 根據當前運算子棧頂的符號來判斷進行何種運算
    switch (s_ch->str[s_ch->top])
    {
        case '+':
            result = a + b;
            break;
        case '-':
            result = b - a;
            break;
        case '*':
            result = a * b;
            break;
        case '/':
            result = b / a;
            break;
    }   
    PUSH_num (s_sum, result);                   // 將運算結果入棧
}

int main()
{
    OP_num sdata;
    OP_ch  soper;

    SETNULL_num (&sdata);
    SETNULL_ch  (&soper);

    int i = 0, len_str, t;

    char str[MAX];
    char str_num[MAX];          // 存放要轉化的數字
    gets (str);                 // 輸入表示式
    len_str = strlen (str);     // 獲取表示式長度

    while (str[i] != '\0')      // 遍歷表示式
    {
        if (is_num(str[i]))     // 判斷是否是數字
        {
            t = 0;
            while (is_num(str[i]))
            {
                str_num[t++] = str[i++];
                //將表示式中的數字進行儲存,用於轉化為對應的整形數
            }
            str_num[t] = '\0';
            PUSH_num (&sdata, atoi(str_num));
            // 遇到算數符號的時候讓符號前面的數進棧
        }
        else
        {
            if (PUSH == jud(&soper, str[i]))
            {
                PUSH_ch (&soper, str[i]);
            }
            else
            {
                if (str[i] != ')')      // ')'不讓其入棧所以單獨列出來討論
                {
                    operate (&soper, &sdata);       // 進行一次運算並一處棧頂運算子
                    Pop_ch(&soper);                 // 符號出棧
                    PUSH_ch (&soper, str[i]);       // 進行壓棧
                    // 相當於用當前的運算子替換了剛才棧頂的運算子號
                }
                else                // 遇到')'
                // 不斷取字元運算 知道遇到 ')'
                {
                    do
                    {
                        operate (&soper, &sdata);
                        Pop_ch (&soper);
                    }while (soper.str[soper.top] != '(');

                    Pop_ch (&soper);
                    // 將‘(’彈出棧空間
                }
            }
            i++;
        }
    }
    while (soper.top != -1)
    {
        operate (&soper, &sdata);
        Pop_ch (&soper);
    }
    printf ("%d\n", sdata.num[sdata.top]);

    return 0;
}