C语言 逆波兰算法实现计算器(源码)



一、逆波兰表达式介绍

概念:
1.前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。如 - × + 3 4 5 6

2.中缀表达式就是常见的运算表达式,如 (3+4)×5-6

3.后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后。如 3 4 + 5 × 6 -

逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。

二、逆波兰表达式的转换和计算

1.运算表达式转换为逆波兰表达式

1、构造一个运算符栈和逆波兰表达式队列
2、读入运算表达式,从左至右依次扫描字符,如果是数字则写入队列,如果是运算符则需要与栈顶运算符进行比较
3、运算符比较规则:
(1)如果运算符栈内为空或者检测到栈顶运算符为 ‘(’ ,则扫描的运算符无条件入栈
(2)如果扫描的运算符优先级比栈顶运算符优先级高,则扫描运算符入栈;反之输出栈顶运算符至表达式队列,再次执行对比操作,直至扫描运算符优先级比栈顶运算符优先级高或者满足第一条规则
(3)如果扫描到运算符为 ‘)’ ,抛弃 ‘)’ 并从栈顶依次输入运算符至队列,直到遇见 ‘(’ ,抛弃 ‘(’ 。
4、最后将栈内剩余运算符输入到队列。
5、逆波兰表达式转换完成。

a+b ---> a,b,+

a+(b-c) ---> a,b,c,-,+

a+(b-c)*d ---> a,b,c,-,d,*,+

a+d*(b-c)--->a,d,b,c,-,*,+

a=1+3 ---> a=1,3 +

例图

2.逆波兰表达式的计算

1、构造一个操作数栈
2、从逆波兰表达式队列中依次读入字符,如果是操作数,则输入到操作数栈。如果是运算符,则对栈顶操作数和次栈顶操作数进行相应的运算并且清除,最后将运算结果入栈。
3、队列扫描并计算结束后,操作数栈内最终数据即运算结果。

三、逆波兰算法的C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

union counter//定义new_res共同体存储波兰表达式
{
    char ch;
    float num;
}new_res[100] = {0};
char res[1000] = {0};//输入的中缀表达式
int flag[100] = {0};//与new_res一一对应的判断数组元素类型的flag数组
int n = 0;//flag下标
int i = 1;//循环判断标志

int element();//将中缀表达式转换为后缀表达式存储与new_res中
int count(union counter new_res[100], int flag[100]);//将波兰表达式计算并输出结果

int main()
{
    while(i)
    {
        element();
        count(new_res, flag);
        printf("您还要继续嘛?继续请输入1,退出请输入0:");
        scanf("%d",&i);
    }
    return 0;
}

int element()
{
    char stack_op[50] = {0};//运算符栈
    char temp[100] = {0};
    int j = 0;
    int m = 0;//运算符栈下标

    n = 0;//循环后重置flag下标
    printf("计算:");
    scanf("%s", res);
    for (int i = 0; i < strlen(res)+1; i++)//strlen(res)+1确保最后一位数据被写入
    {
        if (isdigit(res[i]) || res[i] == '.')
        {
            temp[j++] = res[i];
        }
        else if (!isdigit(res[i]) && (strcmp(temp,"")!=0))//将temp中存储的数据转换为float类型写给new_res
        {
            temp[j] = '\0';
            new_res[n].num = atof(temp);
            flag[n] = 0;
            n++;
            memset(temp,'\0',sizeof(temp));
            j = 0;
        }
        switch (res[i])//判断运算符的优先级决定出栈入栈
        {
        case '(':
            stack_op[m++] = res[i];
            break;
        case '+':
        case '-':
            if (m == 0 || stack_op[m-1] == '(')
            {
                stack_op[m++] = res[i];
            }
            else
            {
                m--;
                new_res[n].ch = stack_op[m];
                flag[n] = 1;
                n++;
                i--;
            }
            break;
        case '*':
        case '/':
            if (m == 0 || stack_op[m-1] !='*' || stack_op[m-1] != '/')
            {
                stack_op[m++] = res[i];
            }
            else
            {
                m--;
                new_res[n].ch = stack_op[m];
                flag[n] = 1;
                n++;
                i--;
            }
            break;
        case ')':
            m--;
            while(stack_op[m] != '(')
            {
                new_res[n].ch = stack_op[m];
                flag[n] = 1;
                n++;
                m--;
            }
            stack_op[m] == 0;
            break;
        default:
            break;
        }
    }
    for (int k = m-1; k >= 0; k--)//将栈中剩余的运算符全部写入new_res
    {
        new_res[n].ch = stack_op[k];
        flag[n] = 1;
        n++;
    }
    
    return 0;
}

int count(union counter new_res[100], int flag[100])
{
    int x = 0;//数据栈下标
    float stack_num[100] = {0};//数据栈
    
    for (int i = 0; i < n; i++)
    {
        switch (flag[i])//判断new_res中的数据类型
        {
        case 0://将数据写入到栈中
            stack_num[x++] = new_res[i].num;
            break;
        case 1://运算
            switch (new_res[i].ch)
            {
            case '+':
                x --;
                stack_num[x-1] += stack_num[x];
                break;
            case '-':
                x --;
                stack_num[x-1] -= stack_num[x];
                break;
            case '*':
                x --;
                stack_num[x-1] *= stack_num[x];
                break;
            case '/':
                x --;
                if (stack_num[x] != 0)
                {
                    stack_num[x-1] /= stack_num[x];
                }
                else
                {
                    printf("除零错误\n");
                    exit(0);
                }
                break;
            default:
                break;
            }
        default:
            break;
        }
    }
    printf("结果:%f\n", stack_num[0]);
    return 0;
}

运行结果:

计算:3*8+2/4-(6+2/1)
结果:16.500000
您还要继续嘛?继续请输入1,退出请输入0:1
计算:9*9-(11-2)+(4/2+6)
结果:80.000000
您还要继续嘛?继续请输入1,退出请输入0:1
计算:3*3/6
结果:1.500000
  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值