栈的应用:算术表达式求值

栈的应用之算术表达式的求值:

思想:                                                                                                                                                        建立两个栈,一个操作数栈,一个运算符栈,遍历算术表达式字符串,读取的是数,将值压入操作数栈中,读取下一个字符;读取的是运算符,将读取运算符与栈顶运算符优先级进行比较:如果栈顶运算符优先级低,则将读取运算符直接压入运算符栈中,然后读取下一个字符。如果栈顶运算符优先级高,则出进行“计算操作”,操作数栈中出栈两个数,假如先出的为a,后出的为b,运算符栈中出一个运算符,假设为op,进行b op a计算,然后将计算结果再压入操作数栈中,一直进行“计算”操作,直到运算符栈顶运算符的优先级比所读取的运算符优先级低,然后将读取运算符压入运算符栈中,读取下一个字符。读取完最后一个字符后,如果运算符栈不为空,则进行“计算”操作,一直到运算符栈为空,最后操作数栈的栈顶数值,即为最终所求的结果。

具体算法思路:用两个栈Oper和Optr来存放读取的操作数和运算符,Optr先压入一个#符号,遍历输入的算术表达式字符串(以#符号结尾)

            1.读取的是操作数字符,因为每次只能读取一个字符,所以需要计算连续的操作数字符的值,压入操作数栈Oper中

            2.读取的是运算符(只有七种:+、-、*、/、(、)、#)

                (1)如果读取的是(、*、/三者之一,直接压入Optr栈中,因为“(”是一个子表达式的开始,而“*”和“/”的优先级是最高的

                   (2)如果读取的是+,-之一,如果Optr栈顶运算符为*或者\,则进行“计算”操作,直到Optr栈顶运算符不为*或者\为止,将+或-压入Optr栈中

                   (3)如果读取的是),则进行“计算”操作,直到Optr栈顶元素为(为止,然后将(出栈

                   (4)如果读取的是#,则进行“计算”操作,直到Optr栈顶元素为#为止,此时即运算完毕

       计算操作:Oper栈先后出两个数a,b,Optr栈中出一个运算符 op,进行b op a的计算,将计算结果压入Oper中即可

       Oper栈顶数值即最终的运算结果。

代码如下:按照自己拆开的思路自己写的,是用顺序栈实现的,有问题还请各位指出哈,新手一枚,第一篇博客。

//算术表达式求值
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define Maxsize 128
#define N sizeof(SqStack)

typedef double ElemType;  //int型的只能求出整数,改成double可求出小数位!!!
typedef struct
{
    ElemType data[Maxsize];   //数据域
    int top;   //栈顶"指针"
}SqStack;

int main(void)
{
    bool push(SqStack * p, ElemType n);    
    ElemType pop(SqStack * p);            //出栈,函数类型是栈元素数据类型
    ElemType getTop(SqStack * p);        //获取栈顶元素,注意函数返回类型也是栈元素数据类型
    ElemType evaluate_a_expression(char* s);   //求s指向字符串算术表达式的值
    char string[Maxsize];
    ElemType result;
    printf("Please input the arithmetic operation expression(don't have Spaces and ends with a # sign):\n");
    scanf("%s", string);
    result = evaluate_a_expression(string);
    printf("the result of arithmetic operation expression: %f", result);
    return(0);
}

SqStack* creat(void)  //创建栈,将top初始化为-1
{
    SqStack* k = (SqStack*)malloc(N);
    k->top = -1;
    return(k);
}

bool push(SqStack* p, ElemType n)  //进栈
{
    //进栈先判断栈满!!!
    if (p->top == Maxsize - 1)
        return(false);
    p->data[++p->top] = n;
    return(true);
}

ElemType pop(SqStack* p)  //出栈
{
    //出栈先判断栈空!!!
    if (p->top == -1)
        return(-1);    //返回-1表示出栈失败
    return(p->data[p->top--]);
}

ElemType getTop(SqStack* p)   //获取栈顶元素
{
    //获取栈顶元素也要判断栈空!!!
    if (p->top == -1)
        return(-1); //返回-1表示取值失败
    return(p->data[p->top]); //直接返回栈顶元素
}

ElemType evaluate_a_expression(char* s)
{
    SqStack* Optr, * Oper;    
    ElemType d, result;
    bool calculate_press(SqStack * Oper, SqStack * Optr);
    Optr = creat();  //运算符栈
    push(Optr, '#');    //字符#先压入栈中
    Oper = creat();        //操作数栈
    for (; *s != '\0'; s++)
    {
        if (*s >= '0' && *s <= '9')
        {
            d = 0;
            while (*s >= '0' && *s <= '9') //用一个循环来计算连续的数字字符组成的值
            {
                d = 10 * d + *s - '0';
                s++;
            }
            s--;  //跳出循环,s指向数字字符的后面字符,为了同步,再--,否则将会跳过读取一个字符
            //将求的值压入Oper栈中
            push(Oper, d);
        }
        else
        {
            if (*s == '(' || *s == '*' || *s == '/')
                push(Optr, *s);    //乘和除优先级最高,(左括号,都直接进操作符栈
            else if (*s == ')')
            {
                while (getTop(Optr) != '(')   //没到左括号,一直计算
                    calculate_press(Oper, Optr);
                pop(Optr);   //左括号出栈
            }
            else if (*s == '#')  
            {
                while (getTop(Optr) != '#')  //还剩有计算没做,继续运算
                    calculate_press(Oper, Optr);
                break;
            }
            else if (*s == '+' || *s == '-')
            {
                char top_element = getTop(Optr);  //取运算符栈顶操作符,与读取的操作符比较优先级
                switch (top_element)
                {
                case '+':
                case '-':
                case '(':
                case '#':
                    push(Optr, *s); 
                    break;   //栈顶元素优先级低,直接将所读操作符入栈,读取下一个
                case '*':
                case '/':  //栈顶元素优先级高,则进行“计算并且压入”操作 
                    do{
                        calculate_press(Oper, Optr);  //先做一次计算
                        top_element = getTop(Optr);  //取新的栈顶运算符
                    }while (top_element == '*' || top_element == '/'); //栈顶元素优先级高则继续计算,直到栈顶元素优先级低,
                    //到栈顶元素优先级低,压入读取元素
                    push(Optr, *s);    
                    break;                    
                }
            }
            else
            {
                printf("error!");
                exit(0);
            }
        }
    }
    result = getTop(Oper);  //操作数栈顶元素即所求结果
    free(Oper);  
    free(Optr);  //操作数栈和运算符栈释放掉
    return(result);
}

//计算函数: 操作数栈中出2个数和运算符栈中出1个操作符做计算,结果压入操作数栈中
bool calculate_press(SqStack* Oper, SqStack* Optr)  
{
    ElemType a, b, result;
    char k = pop(Optr);  //运算符栈中出一个运算符
    a = pop(Oper);
    b = pop(Oper);  //操作数栈中出两个数
    switch (k)
    {
    case '+':
        result = b + a; break;
    case '-':
        result = b - a; break;
    case '*':
        result = b * a; break;
    case '/':    
        if (a == 0)
        {
            printf("The denominator is 0 error!");   //输出错误信息后终止程序
            exit(0);    //该函数在 stdlib.h 的头文件中,与malloc等函数一样
        }
        else
            result = b / a; 
        break;
    }
    push(Oper, result);   //结果压入Oper操作数栈中
    return(true);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值