标题:分享:中缀表达式转后缀表达式
取消只看楼主
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
结帖率:97.5%
已结贴  问题点数:20 回复次数:7 
分享:中缀表达式转后缀表达式
写的一个简单的计算器,能简单+ - * / ^ 运算,没有考虑计算结果溢出问题。
处理了负号运算,合法的负号。只能是第一个数为负数,左括号开头的第一个数为负数,以及括号括起来的负数。
希望各位大牛指点下哪里不足。
程序代码:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define MAXSIZE 10000

struct Stackop
{
    char op[MAXSIZE];
    int top;
}Stackop;

struct Stacknum
{
    double num[MAXSIZE];
    int top;
}Stacknum;

int GetLevel(char op)            //得到运算符优先级
{
    if (op == '+' || op == '-')
        return 1;
    else if (op == '*' || op == '/')
        return 2;
    else if (op == '^')
        return 3;
    else
        return -1;
}

double Caclulate(double a, double b, char symbol, int *flag)
{
    switch (symbol)                        //数据运算,以及除数不能为0
    {
    case '+' :
        return a + b;
    case '-' :
        return a - b;
    case '*' :
        return a * b;
    case '/':
        if (b == 0)
            *flag = 0;
        else
            return  a / b;
        break;
    case '^' :
        return pow(a, b);
    default :
        *flag = 0;
        break;
    }
    return 0;
}

int GetRpn(char *calc, char *rpn)            //中缀表达式转后缀表达式
{
    int len, i, flag, cnt, error;

    error = flag = cnt = 0;
    Stackop.top = -1;                        //字符栈为空
    len = strlen(calc);
    if (calc[len - 1] == '=')                //考虑最后是否为=
        calc[len - 1] = '\0';
    for (i = 0; calc[i] != '\0'; i++)        //将负数和-号区别,负数用!代替
        if (calc[0] == '-' || calc[i] == '-' && calc[i - 1] == '(')
            calc[i] = '!';
    for (i = 0; calc[i] != '\0'; i++)            
    {
        if (isdigit(calc[i]) || calc[i] == '!')            //数字处理过程,如果扫描到的是数字,直接加入到后缀数组中
        {
            if (!isdigit(calc[i]))
            {
                i++;
                flag = 1;
            }
            if (!isdigit(calc[i]))
                return 0;
            
            while (isdigit(calc[i]))
            {
                rpn[cnt++] = calc[i];
                i++;
            }
            if (calc[i] == '.') {
                rpn[cnt++] = calc[i];
                ++i;
                while (isdigit(calc[i]))
                {
                    rpn[cnt++] = calc[i];
                    i++;
                }
            }
            if (flag)                
            {
                rpn[cnt++] = '#';        //如果是负数末尾加#加!,表示一个负数结束
                rpn[cnt++] = '!';
                flag = 0;
            }
            else
            { 
                rpn[cnt++] = '#';        //当是整数末尾加#,表示一个正数结束
            }
        }
        
        if (calc[i] == '\0')
            break;
        if (calc[i] == '(')                //如果是左括号直接进符号栈
            Stackop.op[++Stackop.top] = calc[i];
        else if (calc[i] == ')') {                    //当匹配到右括号出栈
            while (Stackop.op[Stackop.top] != '(')        //如果栈顶是左括号,直接结束,相当于空括号
            {
                rpn[cnt++] = Stackop.op[Stackop.top];    //挨个把括号里面的运算符转换到后缀数组中
                --Stackop.top;
            }                
            --Stackop.top;                        //把匹配到的左括号出栈
        }
        else if (Stackop.op[Stackop.top] != -1 &&  GetLevel(calc[i]) <= GetLevel(Stackop.op[Stackop.top]))
        {                                        //扫描到的运算符如果比栈顶优先级低,栈里所有优先级低于扫描到运算符优先级的运算符
                                                //加入到后缀数组
            while (Stackop.op[Stackop.top] != -1 && (error = GetLevel(calc[i])) <= GetLevel(Stackop.op[Stackop.top]))
            {
                if (error == -1)
                    return 0;
                rpn[cnt++] = Stackop.op[Stackop.top];
                Stackop.top--;
            }
            Stackop.op[++Stackop.top] = calc[i];    //如果符号栈为空,或者栈里优先级大于扫描到的字符优先级,把扫描到的运算符加入字符栈 
        }
        else
            Stackop.op[++Stackop.top] = calc[i];    //字符栈空或者优先级比扫描到的运算符优先级大, 假如到字符栈
        
    }
    while (Stackop.top != -1) {
        rpn[cnt++] = Stackop.op[Stackop.top];    //到最后字符栈还有运算符,一次加入到后缀数组,最后得到后缀表达式
        Stackop.top--;
    }
    rpn[cnt] = '\0';
    return 1;
}

int GetAns(char *rpn, double *result)
{
    int i, flag = 1;
    double num, cnt;
    double a, b, val;

    Stacknum.top = -1;                    //这里开始就是后缀表达式计算过程
    for (i = 0; rpn[i] != '\0'; i++)    //到这里就是入栈和出栈的过程,只要是数字就直接入栈;是字符,数字栈出栈两个元素进行运算后入栈
    {                                    //反复此过程,到最后栈顶元素就只有一个,就是我们要的计算结果

        if (rpn[i] >= '0' && rpn[i] <= '9') {
            num =  0;
            cnt = 1.0;
            while (rpn[i] != '#' && rpn[i] != '.')
            {
                num = num * 10.0 + (rpn[i] - '0');
                i++;
            }
            if (rpn[i] == '.')
            {
                i++;
                    while (rpn[i] != '#')
                    {
                        num = num * 10.0 + (rpn[i] - '0');
                        cnt *= 10;
                        i++;
                    }
            }
            if (rpn[i + 1] == '!')
            {
                i++;
                Stacknum.num[++Stacknum.top] = num / cnt * (-1);    //字符串转换为数字或者浮点数入数字栈
            }
            else
                Stacknum.num[++Stacknum.top] = num / cnt;
        }
        else
        {                        //匹配到运算符,两个数字出栈参加运算再进栈
            b = Stacknum.num[Stacknum.top--];
            if (Stacknum.top == -1)
                return 0;
            a = Stacknum.num[Stacknum.top--];
            val = Caclulate(a, b, rpn[i], &flag);
            Stacknum.num[++Stacknum.top] = val;

        }
    }
    *result = Stacknum.num[Stacknum.top];
    if(!flag)
    return 0;
    return 1;
}

int main()
{
    char calc[MAXSIZE], rpn[MAXSIZE];
    double result;

    while (1)
    {
        printf("Please input calculate expression and expression can't hava special symbols!\n\n");
        scanf("%[^\n]%*c", calc);    //表示读一行,解决scanf不能读空格的问题
        if (!GetRpn(calc, rpn)) 
        {
            printf("\nError: expresion error!\n");
            continue;
        }
        if (GetAns(rpn, &result))
            printf("\nCalculate val = %lf\n\n", result);
        else
            printf("\nError: expresion error!\n");

    }
    return 0;
}


[此贴子已经被作者于2017-5-28 09:42编辑过]

搜索更多相关主题的帖子: 计算器 表达式 
2017-05-27 14:46
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
提示不能输入特殊字符,空格没处理,我直接是scanf输入的,死循环也正常的。5--5数学上也不能这样表示吧

2017-05-27 19:29
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
回复 5楼 renkejun1942
大哥,数学上不能这么表示的。1----1你说是不是非法的表达式。还有那个是循环你是怎么输入的
2017-05-27 19:35
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
回复 7楼 renkejun1942
处理了负号运算,合法的负号。只能是第一个数为负数,左括号开头的第一个数为负数,以及括号括起来的负数。
我记得数学上的负数是这样子的。
2017-05-27 19:40
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
回复 9楼 renkejun1942
好吧,确实多。没有去处理这些。后面再改进
2017-05-27 19:45
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
回复 13楼 renkejun1942
你说这个问题我也不知道怎么回事了。vs和codebloks集成ide的能正常编译调试。mingw编译后调试就出错
2017-05-28 07:45
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
这什么问题
2017-05-28 07:47
Emotiona
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:311
专家分:581
注 册:2017-3-7
得分:0 
回复 16楼 renkejun1942
没有啊。加一个printf函数去找代码断。2分钟就找到了。代码更新了,测试通过。最开始codebloks是不报错的,玩了会就报错了。。。无语。反正vs是永远不报错,尴尬。
2017-05-28 09:45



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-477417-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.453369 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved