藉助棧實現表達式的計算

這兩天要複習準備考試,博客沒有及時更新。另一方面,後綴表達式的轉化及求值的程序始終沒有寫好,讓我異常苦惱,心情也是莫名煩躁。現在表達式求值的程序已基本實現,仍有不足之處需要改進,各位可以參考,由於時間關係,無法細緻講解。將在考完試後的更新中加以補充,各位先看代碼後的註釋吧,註釋還是比較詳細的,代碼如下

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
#define MAXOP 32
typedef char elemtype;
typedef int status;
/*定義運算符優先級*/
typedef struct calc{
    elemtype ch;
    int pri;
}calc;
/*同一運算符在棧內和棧外優先級不同,需要加一個數字進行區分*/
calc inpri[]={{'=',0},{'(',1},{'*',5},{'/',5},{'+',3},{'-',3},{')',6}};
calc outpri[]={{'=',0},{'(',6},{'*',4},{'/',4},{'+',2},{'-',2},{')',1}};

/*定義運算符棧*/
typedef struct sqstack{
    elemtype data[MAXSIZE];
    int top;
}sqstack;

/*定義運算結果棧*/ 
typedef struct value{
    float suffixvalue[MAXSIZE];
    int top;
}value;

/*定義棧操作
***************************************/
status traversestack(sqstack *s){
    int i=0;
    for(i=s->top;i>=0;i--){
        printf("%d ",s->data[i]);
    }
    printf("\n");
}

/*初始化運算符棧*/ 
status initstack(sqstack *s){
    s->top=-1;//置空棧 
}

/*初始化運算結果棧*/ 
status initvstack(value *V){
    V->top=-1;
    return OK;
}

//將元素壓入棧 
status push(sqstack *s,elemtype data)
{
    if(s->top==MAXSIZE-1){
        return ERROR;//判斷棧是否已滿 
    }
    else{
        s->top++;
        s->data[s->top]=data;
    }
    return OK;
}


//返回棧長
status stacklength (sqstack *s){
    return s->top+1;
}

//出棧
status pop(sqstack *s,elemtype * data){
    if(s->top==-1){
        printf("空棧\n");
        return ERROR;
    }
    else{
        *data=s->data[s->top];
        s->top--;
    }
}

/*取棧頂元素*/
status gettop(sqstack *S,elemtype *ch){
    if(S->top==-1)
        return ERROR;
    else
        *ch=S->data[S->top];
        return OK;
}

/*定義棧操作結束 
***************************************/

/*定義運算符相關操作
****************************************/
/*求棧外操作符優先級*/
status Inpri(elemtype op){
    int i=0;
    for(i=0;i<MAXOP;i++){
        if(op==inpri[i].ch)
           return inpri[i].pri;
    }
} 

/*求棧內操作符優先級*/
status Outpri(elemtype op){
    int i=0;
    for(i=0;i<MAXOP;i++){
        if(op==outpri[i].ch)
           return outpri[i].pri;
    }
}

/*判斷兩運算符優先級關係*/
status precede(elemtype opin,elemtype opout){
    if(Inpri(opin)>Outpri(opout))
       return 1;
    else if(Inpri(opin)<Outpri(opout))
       return -1;
    else
       return 0;
}

/*判斷是否爲運算符*/
status isop(elemtype ch){
    if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')')
         return TRUE;
    else
         return FALSE; 
}

/*將中綴表達式轉換爲後綴表達式*/
status trans(char * infix,char suffix[]){
    sqstack S;
    initstack(&S);
    push(&S,'=');/*先讓一個等號入棧,作爲標記*/
    char ch;
    int i=0,j=0;
    while(*infix!='\0'){
        /*是數字的情況*/
        if(!isop(*infix)){
            while((*infix)>='0'&&(*infix)<='9'){
                suffix[j++]=*infix;
                infix++;
            }
            suffix[j++]='#';/*數字與數字之間用空格隔開*/
        }
        /*是運算符的情況*/
        else{
            gettop(&S,&ch);
            switch(precede(ch,*infix)){
                case 1:/*棧頂高於棧外*/
                    suffix[j++]=ch;/*棧頂出棧直到棧頂元素優先級低於棧外爲止*/ 
                    pop(&S,&ch);
                    //infix++;/*向後遍歷*/ 
                    break;
                case 0:/*棧頂等於棧外,只有括號會出現此情況*/ 
                    pop(&S,&ch);/*直接出棧*/ 
                    infix++;
                    break;
                case -1:/*棧頂低於棧外*/ 
                    push(&S,*infix);/*入棧即可*/ 
                    infix++;
                    break;
            }
        } 
    }/*while(*infix!='/0')*/
    /*循環結束,開始輸出後綴表達式*/
    pop(&S,&ch);
    while(ch!='='){/*等號代表了表達式的開頭*/ 
        suffix[j++]=ch;
        pop(&S,&ch);
    }
}

/*計算後綴表達式的值*/
float compute(char suffix[]){
    value V;
    initvstack(&V);
    char ch;
    int t=0;
    float d;
    ch=suffix[t];
    t++;
    while(ch!='\0'){
        /*讓棧頂兩元素出棧進行運算*/
        switch(ch){
            case '+':
                V.suffixvalue[V.top-1]=V.suffixvalue[V.top-1]+V.suffixvalue[V.top];
                V.top--;
                break;
            case '-':
                V.suffixvalue[V.top-1]=V.suffixvalue[V.top-1]-V.suffixvalue[V.top];
                V.top--;
                break;
            case '/':
                if(V.suffixvalue[V.top]){
                    V.suffixvalue[V.top-1]=V.suffixvalue[V.top-1]/V.suffixvalue[V.top];
                    V.top--;
                    break;
                }
                else{
                    printf("除零錯誤\n");
                    return ERROR;
                }
            case '*':
                V.suffixvalue[V.top-1]=V.suffixvalue[V.top-1]*V.suffixvalue[V.top];
                V.top--;
                break;
            /*如果後綴表達式中有數字*/ 
            default:
                d=0;
                while(ch>='0'&&ch<='9'){
                    d=10*d+ch-'0';/*將字符轉換成數字*/ 
                    ch=suffix[t];/*向後遍歷*/ 
                    t++;
                }
                V.top++;
                V.suffixvalue[V.top]=d;/*將轉換好的入棧*/ 
        }
        ch=suffix[t];/*更新ch的值*/
        t++;
    }
    return V.suffixvalue[V.top];/*返回棧頂值作爲運算結果*/ 
}

int main(void){
    char infix[]="(56-20)/(4+2)";
    char suffix[200];
    trans(infix,suffix);
    printf("中綴表達式:%s\n",infix);
    printf("後綴表達式:%s\n",suffix);
    printf("後綴表達式的值爲%f",compute(suffix));
    return 0;
} 

再次吐槽:真心難啊…………

2016-04-21日更新:
今天覆習了表達式求值問題,還是感到存在一些問題,還是對算法的理解理解不夠透徹造成的。
問題主要出現在後綴表達式轉中綴表達式的過程中

status trans(char *infix,char suffix[]){
    elemtype ch;
    sqstack S;
    int i=0;
    initstack(&S);
    push(&S,'=');
    while(*infix!='\0'){
        if(!isop(*infix)){
            while(*infix<='9'&&*infix>='0'){
                suffix[i++]=*infix;
                infix++;
            }
            suffix[i++]='#';
        }
        else{
            gettop(&S,&ch);
            switch(precede(ch,*infix)){
                case 1:
                    suffix[i++]=ch;
                    pop(&S,&ch);
                    break;
                case 0:
                    pop(&S,&ch);
                    infix++;
                    break;
                case -1:
                    push(&S,*infix);
                    infix++;
                    break;
            }
        }
    }/*while(*infix!='\0')*/
    pop(&S,&ch);
    suffix[i]=ch;
    while(ch!='='){
        suffix[i++]=ch;
        pop(&S,&ch);
    }
}

在這段代碼的switch語句中,在處理case 0時,對於括號的優先級的理解有所遺忘。正確的處理方式是當棧外爲右括號,棧內爲左括號時,直接出棧即可。
在compute函數中,忘了寫default語句,導致當遇到後綴表達式中的數字時無法處理。
以上就是今天的錯誤,要引以爲戒。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章