1. 程式人生 > >資料結構——表示式求值(程式碼)

資料結構——表示式求值(程式碼)

表示式求值

C++ 環境codeblocks17 通過

/*
表示式求值,可用運算子 +-/*(){}[]
@CGQ 2018/10/30
*/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<stack>


char compare(char, char);                      //比較運算子優先順序
float Operation(float, float, float );         //實際運算函式
int getnext(float * n);                        //該函式返回0為數字,返回1為運算子
float EvaluateExpression();                    //表示式求值返回結果

int getnext(float * n)                        //該函式返回0為數字,返回1為運算子
{
    char c;
    *n = 0;
    while((c = getchar()) == ' ');          //跳過空格

    if(!isdigit(c))                         //判斷是否是數字
    {   // 不是數字
        if(c=='{'||c=='[')
            *n = '(';
        else if(c=='}'||c==']')
            *n = ')';
        else
            *n = c;
        return 1;
    }
    do
    {
        *n = *n * 10 + (c - '0');           //使用迴圈獲得連續的數字,乘10進位
        c = getchar();
    }
    while(isdigit(c));
    ungetc(c, stdin);                       //讀到一個運算子,將運算子寫回輸入快取
    return 0;
}

/*
對於連續出現的運算子進行比較優先順序
結果有> < =,可以得到+-×/之間的優
先級,加減乘除的優先順序都低於'(',
但是都高於')',並且根據從左到右運算
可知當運算子相同時,第一個大於第二
個,0表示不存在
*/
char compare(char a, char b)
{
    int i, j;
    char pre[7][7] =                        //定義運算子之間的優先順序
    {
        {'>','>','<','<','<','>','>'},
        {'>','>','<','<','<','>','>'},
        {'>','>','>','>','<','>','>'},
        {'>','>','>','>','<','>','>'},
        {'<','<','<','<','<','=','0'},
        {'>','>','>','>','0','>','>'},
        {'<','<','<','<','<','0','='},
    };
    switch(a)
    {
    case '+':
        i = 0;
        break;
    case '-':
        i = 1;
        break;
    case '*':
        i = 2;
        break;
    case '/':
        i = 3;
        break;
    case '(':
        i = 4;
        break;
    case ')':
        i = 5;
        break;
    case '#':
        i = 6;
        break;
    }
    switch(b)
    {
    case '+':
        j = 0;
        break;
    case '-':
        j = 1;
        break;
    case '*':
        j = 2;
        break;
    case '/':
        j = 3;
        break;
    case '(':
        j = 4;
        break;
    case ')':
        j = 5;
        break;
    case '#':
        j = 6;
        break;
    default:
        printf("表示式要以#結尾!!!\n");
        exit(1);
    }
    return pre[i][j];
}

float Operation(float a, float operate, float b)           //實際操作兩個數a,b的運算
{
    float result;
    a = (float)a;
    b = (float)b;

    switch((int)operate)
    {
    case '+':
        result = a + b;
        break;
    case '-':
        result = a - b;
        break;
    case '*':
        result = a * b;
        break;
    case '/':
        result = a / b;
        break;
    }
    return result;
}

float EvaluateExpression()
{
    float c;                                  //儲存輸入快取中的字元或數字
    float flag;                               //從輸入快取中取操作符的返回值,0表示取出數字,1表示取出運算子
    float x;                                  //取棧頂操作符
    char operate;                            //儲存要計算的操作符
    float a, b;                               //存取要計算的運算元
    std::stack<float> ns;
    std::stack<char> os;       //ns為運算元棧,os為運算子棧

    os.push('#');
    flag = getnext(&c);

    x = os.top();
    while((float)c != '#' || (float)x != '#')         //表示式的起始位置都是'#',如果讀取的新的字元和運算子都是'#'說明運算已經結束
    {
        if(flag == 0)                   //返回數字
        {
            ns.push(c);
            flag = getnext(&c);
        }
        else                            //返回運算子
        {
            x = os.top();        //取棧頂運算子
            switch(compare((float)x, (float)c))
            {
            case '<':               //棧頂操作符運算優先順序低
                os.push(c);
                flag = getnext(&c);
                break;
            case '>':               //棧頂運算子優先順序高,先退出兩個資料進行運算,然後將運算結果在存入資料棧
                operate = os.top();
                os.pop();
                a = ns.top();
                ns.pop();
                b = ns.top();
                ns.pop();
                ns.push(Operation(b, operate, a));         //由於壓棧的順序,則應當是先出的運算元在後
                break;
            case '=':               //操作符'('')'緊挨,則直接去除括號
                operate = os.top();
                os.pop();
                flag = getnext(&c);
                break;
            case '0':               //比較結果得出表示式錯誤
                printf("input error!\n");
                exit(1);
            }
        }
        x = os.top();
    }
    c = ns.top();
    return c;

}

int main(void)
{
    float c;
    printf("please input expression (end in #):");
    c = EvaluateExpression();
    printf("result = %f\n", c);
    getchar();
}


/*
測試資料
20-2*(5-1-3*(4-1)-2)-6#
1+(2+3)*[3+6]/{4+5}+{[8*7]}#
1+{[2+3]}#
*/