《面向对象程序设计》第四次作业(考虑优先级的表达式计算)

第四次作业分为三个部分:

  • 实现在cmd中调用.exe文件
  • 计算表达式的值(考虑优先级)
  • 在cmd中传参得到运行结果

第一部分get:实现在cmd中调用.exe文件

886183-20160403104634441-195287352.png

实现方法:
在main函数的括号中写上int argc, char* argv[]

以前也经常看别人的代码里有这一行东西,现在才知道原来是和命令行有关。其中:

argc记录了用户在运行程序的命令行中输入的参数的个数
argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数是命令行后面跟的用户输入的参数
有些时候程序运行时需要提供一些参数。比如copy命令,需要指明源文件和目标文件名,就得通过argc和argv来传递

886183-20160404001636441-1931233435.png

在主函数里修改了input参数为argv[argc-1],调用strcmp函数比较argv[1]-a来实现同行输入不同参数个数的不同处理效果。
(这步折腾了好久,发现好多有趣的bug. 比如在编译运行的时候没有输入任何参数输出了一排.exe的文件位置..控制台表示不管用了,只能在cmd里手动键入调试。每每手滑关了又得一步步cd找文件夹 gg)

本部分参考资料:
int main(int argc,char* argv[])详解


第二部分get:计算表达式的值(考虑优先级)

(代码已上传github: Calculator_ver2.0

在本部分中,考虑了计算的优先级和负数的情况。其中优先级以小括号内运算,乘除运算,加减运算为先后顺序。由于负数的位置只可能出现在字符串首或接在左括号之后,所以在操作的时候没有预处理负数的情况,只是在负号前多加了一位0,即将计算 (-1+2)转化为计算 (0-1+2)。为了确保运算结果的正确性,在这里把减法的优先级提到加法之前。
由于最后只输出栈顶元素,所以栈底多加的那个0无论首个数字为正为负都不会有影响。
以及第一次使用字符串流,真是个好东西_(:зゝ∠)_

实现方法:
step1:将scan类中扫描后的中缀表达式队列转化为后缀表达式后,存入suff队列中。
ps:在测试了多组数据之后发现还是得特判两种负号的情况,前一次代码会出现 -2*2+1*(-2+3)= -5的情况。这是因为-号的优先级低于*,但考虑到正常的减法不能再简单的调整优先级。所以在trans方法中添加了特判了两种位置负号的语句。[04.07补充]
ps:补充了负号出现的第三种位置。类似于:-(-()),所以之前压入空栈的一个0改为有几个负号压入几个0。调泡泡那个很长串的表达式调了很久,又发现了不少bug,由于没有预处理负数所以用了朴素的各种特判解决了(。[04.09补充]

主要代码:

void Calculation::trans(queue<string> str)
{
    string temp = "";
    temp = str.front();

    if(temp == "-")
    {
        minus++;

        str.pop();
        //特判第一个负数
        if(isdigit(str.front()[0]))
        {
            suff.push(str.front());
            str.pop();
            suff.push(temp);
        }
        //-()的情况
        else
        {
            //标记为-<)
            str.front() = "<";
            oper.push(temp);
        }
    }

    //遍历中缀表达式队列
    bool flag = true;
    bool isminus = true;

    while(!str.empty())
    {
        flag = true;
        //读取队列第一个元素
        temp = str.front();
        //若是(,直接入栈
        if(temp == "(" || temp == "<")
        {
            oper.push(temp);
            str.pop();
            if(isdigit(str.front()[0]))
            {
                isminus = false; //不是负数
            }
            flag = false;
        }
        //若是*或/,直接入栈
        if(temp == "*"||temp == "/")
        {
            oper.push(temp);
        }
        //若是+,判断栈顶元素,若低于栈顶元素优先级,则栈顶元素出栈后该元素入栈;否则直接入栈
        if(temp == "+")
        {
            //考虑到负数情况,所以先做减法
            while(!oper.empty()&&(oper.top() == "*"||oper.top() == "/"||oper.top() == "-"))
            {
                suff.push(oper.top());  //进入后缀运算表达式队列
                oper.pop();  //弹出栈顶元素
            }
            oper.push(temp);  //当前元素入栈

        }
        //若是-
        if(temp == "-")
        {
            minus++;

            //括号内有负号的情况
            if(!oper.empty() && oper.top() == "(")
            {
                //负数
                if(isminus)
                {
                    str.pop(); //弹出-号
                    suff.push("0"); //0入队列
                    suff.push(str.front()); //此负数数值入队列
                    suff.push(temp); //-号入队列
                }
                //-()
                else
                {
                    oper.push(temp);
                }
            }
            //该-号为减法符号
            else
            {
                //若-低于栈顶元素优先级,则栈顶元素出栈后该元素入栈;否则直接入栈
                while(!oper.empty()&&(oper.top() == "*"||oper.top() == "/"))
                {
                    suff.push(oper.top());  //进入后缀运算表达式队列
                    oper.pop();  //弹出栈顶元素
                }
                oper.push(temp);  //当前元素入栈

            }
        }
        //若是),则依次弹出栈顶元素直到遇到(
        if(temp == ")")
        {

            while(oper.top()!="(" && oper.top()!="<")
            {
                suff.push(oper.top());
                oper.pop();
            }

            if(oper.top() == "<")
            {
                oper.pop();//弹出<
                suff.push(oper.top());//-号入队列
            }

            oper.pop();

            isminus = true;

        }
        //若是运算数字,则入队列
        else if(isdigit(temp[0]))
        {
            suff.push(temp);
        }

        if(flag)
        {
            str.pop();
        }
    }
    while(!oper.empty())
    {
        suff.push(oper.top());
        oper.pop();
    }
}

step2:扫描后缀表达式队列,若为待计算数字的字符串则用sstream转化为数字后,压入存数字的栈num中;若为计算操作符则弹出num栈顶元素进行计算后再入栈。最终num的栈顶即为运算结果。

主要代码:

int Calculation::calcu()
{
    num.push(resu); //将0压入栈,用以处理负数
    stringstream ss;
    int tempnum;

    while(!suff.empty())
    {
        string temp = suff.front();
        //对栈顶元素进行对应操作运算,运算结果入栈
        if(temp == "+")
        {
            resu = num.top();
            num.pop();
            resu += num.top();
            num.pop();
            num.push(resu);
        }
        if(temp == "-")
        {
            resu = num.top();
            num.pop();
            resu = num.top() - resu;
            num.pop();
            num.push(resu);
        }
        if(temp == "*")
        {
            resu = num.top();
            num.pop();
            resu *= num.top();
            num.pop();
            num.push(resu);
        }
        if(temp == "/")
        {
            resu = num.top();
            num.pop();
            resu = num.top() / resu;
            num.pop();
            num.push(resu);
        }
        //若为数字字符串,则转化为数字后入栈
        else if(isdigit(temp[0]))
        {
            ss << suff.front();
            ss >> tempnum;
            num.push(tempnum);
            ss.clear();
        }
        suff.pop();
    }
    return num.top();
}

本部分参考资料:
前缀、中缀、后缀表达式
c++ 字符串流 sstream(常用于格式转换)


第三部分get:在cmd中传参得到运行结果

愉快地按要求输出了结果。

886183-20160405095011781-1886751486.png

听说不能正确计算出第一反人类表达式的计算器不是好游戏机
886183-20160409172114672-1451203722.png

(来自橘子犇犇博客下评论区的梗)

转载于:https://www.cnblogs.com/thousfeet/p/5349449.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值