[基礎算法]通過後綴表達式實現表達式的計算

要求說明:

(1)從鍵盤接收算術表達式,以“#”表示接收結束;
(2)輸出算術表達式的值;
(3)操作數僅限於非負整數,操作符只能是+、-、*、/、^、(、)
(4)可以判斷表達式的合法性(如括號的匹配)

寫作業時遇到的一道題目,覺得比較麻煩,估計以後會有人遇到相同的問題,就寫了篇博客記錄下來。

主要思路:

(1)先將表達式轉化成後綴表達式
(2)逐個讀取後綴表達式,計算結果

轉化成後綴表達式:

(1)設立操作符棧。
(2)設表達式的結束符爲“#”,預設操作符棧的棧底爲“#”。
(3)若當前字符是操作數,則直接發送給後綴式。
(4)若當前字符爲操作符且優先級大於棧頂操作符,則人棧,否則退出棧頂操作符發送給後綴式。
(5)若當前字符是結束符,則自棧頂至棧底依次將棧中所有操作符發送給後綴式。
(6)“(”對它之前後的操作符起隔離作用,則若當前操作符爲“(”時人棧。
(7)“)”可視爲自相應左括號開始表達式的結束符,則從棧頂起,依次退出棧頂操作
符發送給後綴式直至棧頂字符爲“("止。“(”不發送到後綴式。

轉化成後綴表達式函數代碼:

/*SeqStack *L操作符棧,char *str1讀取的表達式,char *str2返回的後綴表達式*/
void Conversion(SeqStack *S,char *str1,char *str2)
{
    int i=0;
    char *p=str1,e;
    //預設操作符棧的棧底爲“#”
    Push(S,'#');
    while (*p!='\0')
    {
        //若當前字符不是操作符是操作數,則直接發送給後綴式。
        if (!Isoperator(*p))
        {
            str2[i++]=*p;
        }
        else
        {
            if (*p=='(')
                Push(S,*p);
            else if (*p==')')
            {
                while(GetTop(S)!='(')
                {
                    Pop(S,&e);
                    str2[i++]=e;
                }
                Pop(S,&e);  /*pop掉前括號*/
            }
            else if (*p=='#')
            {
                while (!IsEmpty(S))
                {
                    Pop(S,&e);
                    str2[i++]=e;
                }
            }
            else if (Compare(*p,GetTop(S)))
            {
                Push(S,*p);
            }
            else if (!Compare(*p,GetTop(S)))
            {
                Pop(S,&e);
                str2[i++]=e;
                continue;  /*continue應該要加*/
            }

        }
        p++;
    }
    str2[i-1]='\0';  /*#號也存進去了,所以用'\0'覆蓋掉*/
}

完整計算表達式代碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define TRUE 1
#define FALSE 0
#define Stack_Size 50

char ops[8]= {'+','-','*','/','(',')','^','#'}; /*運算符數組*/
int priority[8] = {1,1,2,2,0,0,3,-1};

typedef struct
{
    char elem[Stack_Size];
    int top;
} SeqStack;    /*運算符棧的定義*/

typedef struct
{
    int elem[Stack_Size];
    int top;
} nSeqStack;  /* 運算數棧的定義*/

void InitStack(SeqStack *S)   /*初始化運算符棧*/
{
    S->top =-1;
}

void InitStackn(nSeqStack *S)   /*初始化運算數棧*/
{
    S->top =-1;
}

int IsEmpty(SeqStack *S)    /*判斷棧S爲空棧時返回值爲真,反之爲假*/
{
    return(S->top==-1?TRUE:FALSE);
}

int IsEmptyn(nSeqStack *S)    /*判斷棧S爲空棧時返回值爲真,反之爲假*/
{
    return(S->top==-1?TRUE:FALSE);
}

/*判棧滿*/
int IsFull(SeqStack *S)	    /*判斷棧S爲滿棧時返回值爲真,反之爲假*/
{
    return(S->top==Stack_Size-1?TRUE:FALSE);
}

int IsFulln(nSeqStack *S)	    /*判斷棧S爲滿棧時返回值爲真,反之爲假*/
{
    return(S->top==Stack_Size-1?TRUE:FALSE);
}

int Push(SeqStack *S, char x)   /*運算符棧入棧函數*/
{
    if (S->top==Stack_Size-1)
    {
        printf("Stack is full!\n");
        return FALSE;
    }
    else
    {
        S->top++;
        S->elem[S->top]=x;
        return TRUE;
    }
}

int Pushn(nSeqStack *S, int x)   /*運算數棧入棧函數*/
{
    if (S->top==Stack_Size-1)
    {
        printf("Stack is full!\n");
        return FALSE;
    }
    else
    {
        S->top++;
        S->elem[S->top]=x;
        return TRUE;
    }
}

int Pop(SeqStack *S, char *x)    /*運算符棧出棧函數*/
{
    if (S->top==-1)
    {
        printf("運算符棧空!\n");
        return FALSE;
    }
    else
    {
        *x=S->elem[S->top];
        S->top--;
        return TRUE;
    }
}

int Popn(nSeqStack *S, int *x)    /*運算數棧出棧函數*/
{
    if (S->top==-1)
    {
        printf("運算數棧空!\n");
        return FALSE;
    }
    else
    {
        *x=S->elem[S->top];
        S->top--;
        return TRUE;
    }
}

char GetTop(SeqStack *S)    /*運算符棧取棧頂元素函數*/
{
    if (S->top ==-1)
    {
        printf("運算符棧爲空!\n");
        return FALSE;
    }
    else
    {
        return (S->elem[S->top]);
    }
}

int GetTopn(nSeqStack *S)    /*運算數棧取棧頂元素函數*/
{
    if (S->top ==-1)
    {
        printf("運算符棧爲空!\n");
        return FALSE;
    }
    else
    {
        return (S->elem[S->top]);
    }
}

int Isoperator(char ch)        /*判斷輸入字符是否爲運算符函數,是返回TRUE,不是返回FALSE*/
{
    int i;
    for (i=0; i<8; i++)
    {
        if(ch==ops[i])
            return TRUE;
    }
    return FALSE;
}

int Compare(char c1,char c2)
{
    int m,n;
    /*賦值c1對應的n*/
    if (c1=='+' || c1=='-')
        m=1;
    else if (c1=='*' || c1=='/')
        m=2;
    else if (c1=='(' || c1==')')
        m=0;
    else if (c1=='^')
        m=3;
    else if (c1=='#')
        m=-1;
    /*賦值c2對應的n*/
    if (c2=='+' || c2=='-')
        n=1;
    else if (c2=='*' || c2=='/')
        n=2;
    else if (c2=='(' || c2==')')
        n=0;
    else if (c2=='^')
        n=3;
    else if (c2=='#')
        n=-1;
    return m>n;
}

/*SeqStack *L操作符棧,char *str1讀取的表達式,char *str2返回的後綴表達式*/
void Conversion(SeqStack *S,char *str1,char *str2)
{
    int i=0;
    char *p=str1,e;
    //預設操作符棧的棧底爲“#”
    Push(S,'#');
    while (*p!='\0')
    {
        //若當前字符不是操作符是操作數,則直接發送給後綴式。
        if (!Isoperator(*p))
        {
            str2[i++]=*p;
        }
        else
        {
            if (*p=='(')
                Push(S,*p);
            else if (*p==')')
            {
                while(GetTop(S)!='(')
                {
                    Pop(S,&e);
                    str2[i++]=e;
                }
                Pop(S,&e);  /*pop掉前括號*/
            }
            else if (*p=='#')
            {
                while (!IsEmpty(S))
                {
                    Pop(S,&e);
                    str2[i++]=e;
                }
            }
            else if (Compare(*p,GetTop(S)))
            {
                Push(S,*p);
            }
            else if (!Compare(*p,GetTop(S)))
            {
                Pop(S,&e);
                str2[i++]=e;
                continue;  /*continue應該要加*/
            }

        }
        p++;
    }
    str2[i-1]='\0';  /*#號也存進去了,所以用'\0'覆蓋掉*/
}

int Calc(char *str)
{
    nSeqStack *n,nn;
    n=&nn;
    int i;
    int x,y,result;
    char *p=str;
    InitStackn(n);
    while (*p!='\0')
    {
        if (!Isoperator(*p))
        {
            Pushn(n,*p-'0');
        }
        else
        {
            Popn(n,&x);
            Popn(n,&y);
            switch (*p)
            {
            case '+':
                result=y+x;
                break;
            case '-':
                result=y-x;
                break;
            case '*':
                result=y*x;
                break;
            case '/':
                result=y/x;   /*假設都能整除*/
                break;
            case '^':
                result=y;
                for (i=1;i<x;i++)
                {
                    result=result*y;
                }
                break;
            default:
                printf("error\n");
                break;
            }
            Pushn(n,result);
        }
        p++;
    }
    return result;
}

int main()
{
    /*
     *整體步驟
     *(1)表達式轉化成後綴表達式
     *(2)表達式逐個讀取進行計算
     */
    char str1[100],str2[100];
    scanf("%s",str1);
    SeqStack *s,ss;
    s=&ss;
    InitStack(s);
    Conversion(s,str1,str2);
    printf("後綴表達式:%s\n",str2);
    int result = Calc(str2);
    printf("表達式結果:%d\n",result);
    return 0;
}

附:

利用後綴表達式求解,只需要從左向右依次掃描表達式,
(1)遇到操作數人棧,
(2)遇到操作符.則做出棧兩次,獲得兩個操作數,
後出棧的操作數爲第一個操作對象,對它們進行計算,
計算結果作爲下次運算的操作數入棧。
重複上述操作,直到後綴表達式讀取結束,既可完成表達式的計算。

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