[基础算法]通过后缀表达式实现表达式的计算

要求说明:

(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 
#include 
#include 
#include 
#include 
#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)遇到操作符.则做出栈两次,获得两个操作数,
后出栈的操作数为第一个操作对象,对它们进行计算,
计算结果作为下次运算的操作数入栈。
重复上述操作,直到后缀表达式读取结束,既可完成表达式的计算。

你可能感兴趣的:([基础算法]通过后缀表达式实现表达式的计算)