数据结构上机题——使用C++和栈实现简易计算器

下面介绍两种使用C++和栈实现简易计算器的代码,主要参照 c++利用栈实现简单计算器利用栈实现简易计算器(含代码)C++利用栈实现计算器 三篇博文进行的总结和归纳,如有需要可以点击链接查看原文。

方法一:

       使用两个栈结构,一个存数字,一个存运算符。
       为了实现用栈计算算数表达式的值,需设置两个工作栈:用于存储运算符的栈fn,以及用于存储操作数及中间结果的栈num。
计算步骤:

  1. 定义index对表达式进行扫描; 创建两个栈,一个栈存放数字,称为数栈(num);一个栈存放符号,称为符号栈(fn);
  2. 当遇到数字时,入数栈;(注意字符位数,数字有可能是多位数)
    2.1 若是字符串最后一个的时候,直接入数栈
    2.2 若不是最后一个字符,需要再往后判断一位,若后一位不是符号,继续遍历,并将该字符拼接;若是则进数栈
  3. 当遇到符号时,入符号栈
       3.1如果符号栈为空,则直接入栈
       3.2如果符号栈不为空;则需要判断优先级;
           3.2.1判断优先级,若当前符号的优先级小于栈顶符号的优先级,则栈顶符号出栈,同时数栈中两个数字出栈;进行计算,得出的结果入数栈,当前符号入栈。
           3.2.2若优先级大于前一个符号,则继续进行入栈操作。
  4. 当表达式遍历完后,则两个数字、一个符号依次出栈,进行操作,最后栈中剩的最后一个数为结果

代码部分

#include<bits/stdc++.h>
using namespace std;
int prio(char ch)   //运算符优先级判定
{
    switch(ch)
    {
    case '+':
    case '-':
        return 1;
    case '*':
    case '/':
        return 2;
    case '(':
        return 3;
    case ')':
        return 4;
    }
}
double oper(double a,double b,char ch)   //进行运算
{
    switch(ch)
    {
    case '+':
        return a+b;
    case '-':
        return a-b;
    case '*':
        return a*b;
    case '/':
        return a/b;
    }
}
int main()
{
    stack<double>num;  //用来存储运算数字
    stack<char>fh;     //用来存储运算符
    string ll;
    cin>>ll;
    double dit=0;
    for(int i=0;i<ll.size();i++){
        if(ll[i]>='0'&&ll[i]<='9')  //截取数字
        {
            dit=dit*10+(ll[i]-'0');
            if(ll[i+1]<'0'||ll[i+1]>'9'||i==ll.size()-1){    //当下一位为符号时或当前位为最后一位时
                    num.push(dit);
                    dit=0;
            }
        }
        else{
            if(fh.size()==0){           
                    fh.push(ll[i]);
                    continue;
            }
            else{
                if(prio(ll[i])==4){     //处理括号部分
                    while(fh.top()!='(')
                    {
                        char tt=fh.top();
                        fh.pop();
                        double b=num.top();
                        num.pop();
                        double a=num.top();
                        num.pop();
                        num.push(oper(a,b,tt));
                    }
                    fh.pop();  //将左括号弹出栈
                    continue;
                }
                else if(prio(ll[i])<=prio(fh.top())&&prio(fh.top())!=3)  //当前运算符的优先级低于或等于栈顶运算符优先级时
                {
                    char tt=fh.top();
                    fh.pop();
                    fh.push(ll[i]);
                    double b=num.top();
                    num.pop();
                    double a=num.top();
                    num.pop();
                    num.push(oper(a,b,tt));
                    continue;
                }
                else
                {
                    fh.push(ll[i]);
                }
            }
        }
    }
    while(!fh.empty())
    {
        char tt=fh.top();
        fh.pop();
        double b=num.top();
        num.pop();
        double a=num.top();
        num.pop();
        num.push(oper(a,b,tt));
   }
    //cout<<num.size()<<endl;
    //cout<<fh.size()<<endl;
    cout<<num.top()<<endl;
    return 0;
}

方法二:

    先使用一个符号栈来将中缀表达式转换为后缀表达式,再使用一个数字栈来计算后缀表达式的结果。

整体步骤

  1. 中缀表达式转后缀表达式
  2. 计算后缀表达式

第一步:中缀表达式转后缀表达式
       自左向右读入中缀表达式

  1. 若为数字时,加入后缀表达式;
  2. 运算符:
    若为 ‘(’,入栈
    若为 ‘)’,则依次把栈中的的运算符加入后缀表达式中,直到出现’(’,从栈中删除’(’
    若为除括号外的其他运算符, 当其优先级高于除’('以外的栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或者遇到了一个左括号为止,然后将其自身压入栈中(先出后入)。
  3. 当扫描的中缀表达式结束时,栈中的的所有运算符出栈;

具体示意图如下:
在这里插入图片描述
第二步: 计算后缀表达式
       建立一个栈S 。从左到右读表达式,如果读到操作数就将它压入栈S中,如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项按操作数运算,再将运算的结果代替原栈顶的n项,压入栈S中 。如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束。
简言之:

  1. 从左到右读表达式
  2. 遇到操作数压入栈中
  3. 遇到操作符取并弹出栈顶n个元素,(n取决于操作符是n元操作符),计算结果压入栈中
  4. 后缀表达式读完,当前栈顶元素及为结果

C++代码实现

#include <iostream>
#include<stack>

#include <sstream>
#include<stdlib.h>
using namespace std;

double CalSuffix(string suffix)
{
    double result;
    stack<double> number;
    int i = 0,j;
    int n=0;//判断是否为数字
    string current;
    while(suffix[i]!='#')
    {
        int isNum=0;
        if(suffix[i]=='|')
        {
            for(j=i+1;; j++)
            {
                if(suffix[j]=='|')
                    break;
                if(suffix[j]=='#')
                    break;
            }

            //获取|A|之间元素
            for(int k=i+1; k<j; k++)
            {
                current+=suffix[k];
            }

            //判断是否为数值
            for(int k=0; k<current.size(); k++)
            {
                if(current[k]>=48 && current[k]<=57)//数字
                {
                    //strinf转double
                    istringstream iss(current);
                    double num;
                    iss >> num;
                    number.push(num);
                    isNum = 1;
                    break;
                }
            }
            if(isNum!=1){
                double n2 = number.top();
                number.pop();
                double n1 = number.top();
                number.pop();
                if(current=="+"){
                    number.push(n1+n2);
                }
                else if(current=="-"){
                    number.push(n1-n2);
                }
                else if(current=="*"){
                    number.push(n1*n2);
                }
                else if(current=="/"){
                    number.push(n1/n2);
                }
            }
            current="";//清空当前字符串;
        }

        i++;
    }
    if(number.size()!=1)
        cout<<"输入有误"<<endl;
    // else
    return number.top();

}


int Priority(char operate)//栈中优先级
{
    switch(operate)
    {
    case '+':
    case '-':
        return 2;
    case '*':
    case '/':
        return 3;
    case '(':
    case ')':
        return 1;
    default:
        return 0;
    }
}

string Infix2Suffix(string Infix)
{
    stack<char> operate;
    string Suffix = "                               ";//初始化后缀表达式
    char currentOp;
    int negative;
    int i = 0,j = 0;//i为中缀当前指向 j为后缀当前指向
    while(Infix[i]!='\0')
    {
        if(i+1!='\0')
            negative = 0;
        if(Infix[i]>=48 && Infix[i]<=57) //判断数字
        {
            Suffix[j++] = '|';//j是后缀表达索引
            Suffix[j++] =Infix[i];//存储当前数字并指向下一个
            while(Infix[++i]>=48 && Infix[i]<=57) //整数部分
            {
                Suffix[j++] =Infix[i];
            }
            if(Infix[i]=='.') //是小数
            {
                Suffix[j++]='.';
                i+=1;//中缀索引 往后移
                while(Infix[i]>=48 && Infix[i]<=57) //小数部分
                {
                    Suffix[j++] =Infix[i];
                    i+=1;
                }
            }
        }
        else if(Infix[i]=='(')//如果读入(,因为左括号优先级最高,因此放入栈中,但是注意,当左括号放入栈中后,则优先级最低。
        {
            operate.push(Infix[i++]);
        }
        else if(Infix[i]==')')//如果读入),则将栈中运算符取出放入输出字符串,直到取出(为止,注意:()不输出到输出字符串。
        {

            if(operate.empty())//没有左括号
                cout<<"表达式错误"<<endl;
            else
            {
                currentOp = operate.top();
                while(currentOp!='(')
                {
                    cout<<currentOp<<endl;
                    Suffix[j++]='|';
                    Suffix[j++]=currentOp;
                    operate.pop();
                    if(operate.empty())
                    {
                        cout<<"表达式错误"<<endl;
                        break;
                    }
                    currentOp = operate.top();
                }
                operate.pop();//删除栈中(
                i++;
            }
        }

        else if(Infix[i]=='+'||Infix[i]=='-'||Infix[i]=='/'||Infix[i]=='*')
        {
            //判断负数
            if(Infix[i]=='-')
            {

                if(i==0)//第一个为‘-’时为负号
                    negative = 1;
                else if(Infix[i-1]=='+'||Infix[i-1]=='-'||Infix[i-1]=='/'||Infix[i-1]=='*')//如果前面有操作符则为负号
                    negative = 1;
                if(negative==1)
                {
                    Suffix[j++] = '|';//负号
                    Suffix[j++] = '-';
                    i+=1;
                    if(Infix[i]>=48 && Infix[i]<=57) //判断数字
                    {
                        Suffix[j++] =Infix[i];
                        while(Infix[++i]>=48 && Infix[i]<=57) //整数部分
                        {
                            Suffix[j++] =Infix[i];
                        }
                        if(Infix[i]=='.') //是小数
                        {
                            Suffix[j++]='.';
                            i+=1;
                            while(Infix[i]>=48 && Infix[i]<=57) //小数部分
                            {
                                Suffix[j++] =Infix[i];
                                i+=1;
                            }
                        }
                    }
                    continue;
                }
            }

            //如果读入一般运算符如+-*/,则放入堆栈,但是放入堆栈之前必须要检查栈顶
            if(operate.empty())
            {
                operate.push(Infix[i++]);
            }
            else
            {
                char top = operate.top();//栈顶
                if(Priority(top)<Priority(Infix[i])) //放入的符号优先级低于栈顶
                {
                    operate.push(Infix[i++]);//放入栈顶并指向下一个
                }
                else//如果放入的优先级较低,则需要将栈顶的运算符放入输出字符串。
                {
                    while(Priority(top)>=Priority(Infix[i]))
                    {
                        Suffix[j++]='|';
                        Suffix[j++]=top;
                        operate.pop();
                        if(!operate.empty())
                        {
                            top = operate.top();
                        }
                        else
                            break;
                    }
                    operate.push(Infix[i++]);//放入栈顶并指向下一个
                }
            }

        }
        else
        {
            cout<<"符号错误"<<endl;
            i+=1;
        }
    }

    //顺序读完表达式,如果栈中还有操作符,则弹出,并放入输出字符串。
    while(!operate.empty())
    {
        char to = operate.top();
        Suffix[j++]='|';
        Suffix[j++]=to;
        operate.pop();
    }
    Suffix[j] = '#';//结束符
    cout<<Suffix<<endl;
    return Suffix;
}

int main()
{
    string a;
    cin>>a;
    istringstream iss(a);
    double num;
    iss >> num;
    cout<<num;
    cout<<"后缀为:"<<Infix2Suffix(a)<<endl;
    cout<<CalSuffix(Infix2Suffix(a));
    return 0;
}

Reference

方法1原文链接: c++利用栈实现简单计算器
方法1理论链接: 利用栈实现简易计算器(含代码)
方法2原文链接: C++利用栈实现计算器

  • 0
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值