使用C++开发的逆波兰式计算器

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本人代码小白一个,在学校期间进行课程设计,网上资源繁多,但精品甚少,本着人人为我,我为人人的想法,把我以前完成过的课程设计发出来供大家参考。


一、项目背景

设计一个计算器,该计算器主要是用来进行数学计算,用过输入的数据进行运算,得出我们所需要的计算结果。采用的是栈的基本操作,通过栈实现先乘除后加减,括号优先的原则,得到用户所需要的结果,满足更多人的需求,增加计算器的可实用性。

二、项目功能

  1. 计算器可以进行基本运算
  2. 可以自动判断加减乘除优先级
  3. 可超大数据计算
  4. 可以判断用户的错误输入并且进行限制 提示,比如:输入的左右括号不匹配,除数为零,输入非法字符时,都会有相应的提示。

三、代码实现

#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
#include<iostream>
#include<cstdlib>

#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define MAXSIZE 100

using namespace std;
typedef  int Status;

typedef struct StackNode
{
    int data;
    struct StackNode *next;
    int stacksize;//栈可用的最大容量
} StackNode,*LinkStack;

StackNode *p;

LinkStack OPND;
LinkStack OPTR;
LinkStack S;
char str[100];

//栈的初始化
Status InitStack (LinkStack &S)
{
    S=NULL;
    return OK;
}

//判断是否为空栈
bool StackEmpty(LinkStack S)
{
    if (!S)
        return true;
    return false;
}

//入栈
Status Push(LinkStack &S,int e)
{
    //在栈顶插入元素e
    p=new StackNode;//生成新的节点
    p->data=e;//将新数据域置为e
    p->next=S;//将新的元素插入栈顶
    S=p;//修改栈顶指针为p
    return OK;
}

//出栈
int Pop(LinkStack &S,int e)
{
//删除S栈顶元素,用e返回其值
    if(S==NULL)
        return ERROR;//栈空
    e=S->data;//将栈顶元素赋值给e
    p=S;//用p临时保存栈顶空间,以被释放
    S=S->next;//修改栈顶指针
    delete p;//释放原栈顶元素的空间
    return e;
}

//取栈顶元素
int GetTop(LinkStack S)
{
    //返回S的栈顶元素,不修改栈顶指针
    if(S!=NULL) //栈非空
        return S->data;//返回栈顶元素的值,栈顶指针不变
}

//字符的判断
int ln(char ch)
{
    if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#')
        return 1;
    else if(ch>='0'&&ch<='9')
        return 0;
    else
        return -1;

}

char Precede(char theta1, char theta2)  //判断运算符优先级
{
    if ((theta1 == '(' && theta2 == ')') || (theta1 == '#' && theta2 == '#'))
    {
        return '=';
    }
    else if (theta1 == '(' || theta1 == '#' || theta2 == '(' || (theta1
             == '+' || theta1 == '-') && (theta2 == '*' || theta2 == '/'))
    {
        return '<';
    }
    else
        return '>';
}

//对两个数进行运算
int Operate(int a,char c,int b)
{
    int t;
    switch(c)
    {
    case '+':
        t=a+b;
        break;
    case '-':
        t=a-b;
        break;
    case '*':
        t=a*b;
        break;
    case '/':
        if(b==0)
        {
            printf("除数不能为零!\n");
            return 0;
        }
        else
        {
            t=a/b;
            break;
        }
    }
    return t;   //返回计算结果
}

int conversion(int N)  //对于任意一个非负十进制数,打印输出与其等值的八进制数
{
    int e;
    InitStack(S); //初始化空栈S
    while (N) //当N非零时,循环
    {
        Push(S, N % 8); //把N与8求余得到的八进制数压入栈S
        N = N / 8; //N更新为N与8的商
    }
    while (!StackEmpty(S)) //当栈S非空时,循环
    {
        e=Pop(S, e); //弹出栈顶元素e
        cout << e; //输出e
    }
    return N;
}

int Matching()
{
//检验表达式中所含括号是否正确匹配,如果匹配,则返回true,否则返回false
//表达式以“=”结束
    char ch;
    int i=0;
    int x;
    InitStack(S);//初始化空栈
    int flag=2;//标记匹配结果以控制循环及返回结果
    gets(str);   //读入第一个字符
    while(str[i]!='#'&&flag)//假设表达式以“#”结尾
    {
        ch=str[i];
        switch(ch)
        {
        case '(':    //若是左括号,则将其压入栈
            Push(S,ch);
            flag=1;
            break;
        case ')':   //若是“)”,则根据当前栈顶元素的值分情况考虑
            if(!StackEmpty(S)&&GetTop(S)=='(')
            {
                Pop(S,x);//若栈非空且栈顶元素是“(”,则正确匹配
                flag=1;
            }
            else
                flag=0; //若栈空或栈顶元素不是“(”,则错误匹配
            break;
        }        //switch
        i++;  //继续读入下一个字符
    }            //while
    if (StackEmpty(S)&&flag==1)
        return 1;
    else if(!StackEmpty(S)&&(flag==0||flag==1))
        return 0;
    else
        return 2;
}

int EvaluateExpression()
{
//算术表达式求值的算法优先算法,设OPTR和OPEN分别为运算符站和操作数栈
    InitStack(OPND);//初始化open栈
    InitStack(OPTR);//初始化OPTR栈
    Push(OPTR,'#');//将表达式起始符“#”压入OPTR栈底
    char ch,theta,x;
    int a,b,t,i=0;
    string T="";
    while(str[i]!='#' || GetTop(OPTR)!='#')//将表达式没有扫描完成的OPTR的栈顶元素不为“#”
    {
        if(ln(str[i])==0)
        {
            //ch不是运算符则进OPND栈并读取下一个字符
            T+=str[i];
            //cout<<"T+"<<str[i]<<endl;
            i++;
        }
        else if(ln(str[i])==1)
        {
            int res=0;
            for(int j=0; j<T.length(); j++)
            {
                res=res*10+T[j]-'0';
            }
            //cout<<res<<endl;
            if(res||(T[0]=='0'&&T.length()==1))
                Push(OPND,res);
            T.clear();
            switch(Precede(GetTop(OPTR),str[i]))
            {
            case'<':
            {
                Push(OPTR,str[i]);//当前字符ch压入OPTR栈,读入下一个字符
                i++;
                break;
            }
            case'>':
            {
                theta=Pop(OPTR,x);//弹出OPTR栈顶的运算符
                a=Pop(OPND,x);//弹出OPND栈顶的两个运算数
                b=Pop(OPND,x);
                //cout<<b<<(char)theta<<a<<endl;
                Push(OPND,Operate(b,theta,a));//将运算结果压入OPND栈
                break;
            }
            case'='://OPTR的栈顶元素是“(”且ch是“)”
            {
                Pop(OPTR,x);//弹出OPTR栈顶的“(”,读入下一个字符ch
                i++;
                break;
            }
            }

        }
        else if(ln(str[i])==-1)
        {
            printf("输入了非法字符!");
            return -1;
        }
    }
    printf("计算结果为:%d",GetTop(OPND));//因为OPND里的数据为字符型,则再将其转化为整型
}

int menu()
{

    int c;
    cout << "1.(整数)多项式计算" << endl;
    cout << "2.十进制转换为八进制计算" << endl;
    cout << "0.退出\n" << endl;
    cout << "选择:";
    cin >> c;
    getchar();
    return c;
}

main()
{
    printf("*****************************\n");
    printf("*----------逆波兰-----------*\n");
    printf("#            式             #\n");
    printf("*----------计算器-----------*\n");
    printf("*****************************\n");
    while(1)
    {
        switch(menu())
        {
        case 1:
        {
            printf("请输入要计算的表达式:(以#结束)\n");
            int flag = (int) Matching();
            if (flag==1)
            {
                cout << "括号匹配成功!" << endl;
                EvaluateExpression();
                cout <<endl <<endl;
            }
            else if(flag==0)
            {
                cout << "括号匹配失败!" << endl<< endl;
            }
            else
            {
                EvaluateExpression();
                cout <<endl <<endl;
            }
        }
        break;
        case 2:
        {
            int n;
            cout << "输入一个非负十进制数:" << endl;
            cin >> n;
            conversion(n);
            cout <<endl <<endl;
        }
        break;
        case 0:
            cout << "退出成功\n" << endl;
            exit(0);
        default:
            break;
        }
    }
}


总结


代码如上,如果能有所帮助,可以点个赞支持一下,谢谢。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
逆波兰式也称为后缀表达式,是一种不含括号的数学表达式。其计算顺序与中缀表达式相同,但是可以通过栈来实现计算。 下面是用 C++ 实现逆波兰式的生成和计算的示例代码: ```c++ #include <iostream> #include <stack> #include <string> #include <vector> using namespace std; int main() { // 输入逆波兰式 string rpn; cout << "请输入逆波兰式:" << endl; getline(cin, rpn); // 将逆波兰式拆分为操作数和操作符 vector<string> tokens; string token = ""; for (int i = 0; i < rpn.length(); i++) { if (rpn[i] == ' ') { tokens.push_back(token); token = ""; } else { token += rpn[i]; } } tokens.push_back(token); // 计算逆波兰式 stack<int> numStack; for (int i = 0; i < tokens.size(); i++) { string token = tokens[i]; if (token == "+" || token == "-" || token == "*" || token == "/") { int num2 = numStack.top(); numStack.pop(); int num1 = numStack.top(); numStack.pop(); int result; if (token == "+") { result = num1 + num2; } else if (token == "-") { result = num1 - num2; } else if (token == "*") { result = num1 * num2; } else if (token == "/") { result = num1 / num2; } numStack.push(result); } else { int num = stoi(token); numStack.push(num); } } // 输出结果 cout << "计算结果:" << numStack.top() << endl; return 0; } ``` 这个程序首先要求用户输入一个逆波兰式,然后将其拆分为操作数和操作符。接着,程序使用一个栈来计算逆波兰式的值。对于每个操作符,程序将栈顶的两个数弹出,计算后将结果压回栈中。对于每个操作数,程序将其转换为整数并压入栈中。最后,程序输出计算结果。 注意,这个程序没有对输入的逆波兰式进行任何错误检查,如果输入的逆波兰式不符合规范,程序可能会出错。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值