zoukankan      html  css  js  c++  java
  • 《面向对象程序设计》第四次作业(考虑优先级的表达式计算)

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

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

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

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

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

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

    在主函数里修改了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中传参得到运行结果

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

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

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

  • 相关阅读:
    实训9.4.前端:url、href、src,link和@import
    实训9.2.作业1.写一个10次循环,每次得到一个随机数,放进一个集合中,如果这个数已经存在集合中则跳过,最后打印集合中的数字.
    实训9.3. SQL——STRUCTURED QUERY LANGUAGE(结构化查询语言 )
    实训9.2.类集,Collection接口
    实训9.2.IDEA ——java编程语言开发的集成环境(集成开发工具)
    实训9.2. JDK——java语言的软件开发工具包(JAVA的运行环境(JVM+Java系统类库)和JAVA工具) 【java开发的核心】
    从键盘输入数据
    error
    ubuntu 14.04, Command "/usr/bin/python -u -c "import setuptools, tokenize;__file__='
    用Python徒手写线性回归
  • 原文地址:https://www.cnblogs.com/thousfeet/p/5349449.html
Copyright © 2011-2022 走看看