zoukankan      html  css  js  c++  java
  • 第四次作业---计算器的第二步

    1、作业的具体问题网址:

    http://www.cnblogs.com/fzuoop/p/5326667.html

    2、个人认为问题的难点

    • 创建calculation类,作用是调用scan类传出的queue,进行基本的运算,其中包含了加,减,乘,除,以及括号的运用,难点就在于,你根本不知道要怎么做,如果是简单的加减乘除或许多想几种情况,暴力可以做出,但是加入了括号后很多情况都变了。

    • 如何使用命令行来调用代码,从而做到使用代码。(其中还需要明白如何在main函数中传入参数)

    3、针对难点我怎么解决

    • 创建calculation类是这次作业的核心,可以说是百分八十的比重吧,而一开始我根本就不明白如何去做,因为我想的解决方法都被括号这东西硬生生的消灭了,也是我上网去百度了别人的计算器代码,准备看下别人是怎么想的,可是在看完各式各样的代码后的我还是一脸蒙蔽,实在没法子的我去请教同学了,于是她给我推荐了前缀,后缀,中缀,叫我去百度下这个东西,再去慢慢体会,于是我去百度了,看完别人写的有关前缀,中缀,后缀的博客后(后面的参考文件中会贴上网站),我恍然大悟,原来就是这样啊。。。。一切都变的简单了许多,计算器也不再那么神秘,于是很快我就把calculation类敲好了,当然基本的内容是没什么错误了,但是在运行后还是多多少少有编译方面的错误。(其中最坑爹的就是在最后计算的时候调用完成员后没有pop栈顶,导致了死循环,这个浪费了我很多时间)

    • 如何调用命令行,这方面还是有点奇怪,因为我翔跟我说main函数带参数,其实就相当于main是个函数,传入参数,这很好理解,而看了我翔给我的博客(参考文件中会贴出)我也明白了,但是实际运用时就出现问题了,当输入-a时候就炸了,看了半天也没发现错误,于是就用另一种方式,也就是直接cin,而忽略了参数的实际作用,这点我是觉得不好,因为没有实际实现参数的存在意义。

    4、贴出代码,scan类和print类在之前的随笔中已经贴过了,这里就不贴了,主要就是贴calculation类和main函数。

    calculation类的头文件

    #include <iostream>
    #include <queue>
    #include<stack>
    #include<sstream>
    #include<string>
    #include<string>
    using namespace std;
    
    class Calculation
    {
    	public:
    		double  Calculate(queue<string>que);    //用于将输入的queue进行计算 
    };
    
    

    calculation类的cpp文件

    #include"Calculation.h"
    
    double  Calculation::Calculate(queue<string>que)
    {
    	stack<string>operat;                                             //用来存运算符的 
    	stack<string>number;                                             //用来存数字的 
    	stack<double>num;                                                //用来最后计算的 
    	double i,j,k;                                                   //用来在计算时提取stack内的数字,用于计算 
        string temp="",material="";                                     //单纯的用来用来做替代的
    	while(!que.empty())                                             //先把传入的队列从中缀改成后缀 
        {
         	temp=que.front();
         	if(temp=="(")
         	{
         	    operat.push(temp);                                                       
         	    que.pop();
         	    if(que.front()=="-")                                   //用来判断是否是负数的负号,而不是减号 ,因为如果在左括号后有负号就一定是负数的负号 
         	    {
         	    	number.push("0");                                   /* 如果是负号的负数的话就可以再数字之前传入一个0,
    				                                                      这样把符号当做减号,0减去一个数就相当于其相反值 */ 
         	    	temp=que.front();                                   //这里把负号当做减号 
    				operat.push(temp);
    				que.pop();                                         //去除掉这个负号 
    			}
    		}
    		else if(temp==")")                                         /*碰到右括号要去符号stack中去从后往前找,直到找到左括号,
    		                                                            而这之间的符号就push到数字stack中 */ 
    		{
    			for(;;)
    			{
    				if(operat.top()=="(")
    				{
    					operat.pop();                                  //当然要记得把左括号去掉 
    					que.pop();
    					break;
    				}
    				else
    				{
    					material=operat.top();                        //用来把括号之间的运算符存储入numberstack中 
    					number.push(material);
    					operat.pop();
    				}
    			}
    		}
    		else if(temp=="+" || temp=="-")
    		{
    			for(;;)
    			{
    				if(operat.empty() || operat.top()=="(")           //加号和减号只能在运算符stack为空时或者在栈顶为左括号时候导入堆中 
    			    {
    				    operat.push(temp);
    				    que.pop();
    				    break;
    			    }
    			    else
    			    {
    			    	material=operat.top();
    			    	number.push(material);
    			    	operat.pop();
    				}
    			}
    		}
    		else if(temp=="*" || temp=="/")                
    		{
    		    for(;;)
    			{
    			    if(operat.empty() || operat.top()=="(" || operat.top()=="-" || operat.top()=="+")          
    			    
    				 /*只有当堆顶是除号或者乘号的时候才需要将运算符stack的栈
    			     顶转入numberstack中,直到碰到堆顶不是乘号或者除号 */
    			     
    			    {
    			    	operat.push(temp);
    				    que.pop();
    				    break;
    			    }
    		      	else
    			    {
    			        material=operat.top();
    			    	number.push(material);
    			    	operat.pop();
    			    }
    		    }
    	    }
    		else                                                                   //如果不是符号数就是数字了,此时还要和mark相加,因为有可能是负数 
    		{
    			number.push(temp);
    			que.pop();
    		}
    	 }
    	
    	
    	 while(!operat.empty())                                                    //把最后的一些运算符都存入number中 
    	 {
    	 	temp=operat.top();
    	 	number.push(temp);
    	 	operat.pop();
    	 }
    	
    	
    	
    	 while(!number.empty())                                                    //把number堆中的东西反过来存到operat中,用于计算 
    	 {
    	 	operat.push(number.top());
    		number.pop();
    	 }
    	
    	double d=0;                                                                /*以免出现-(100+9)这种情况的出现 这个很重要,
    	                                                                           如果第一个不是-(这种类型的话,也无影响 */
    	num.push(d);
    	
    	while(!operat.empty())                                                     //进行计算 
    	{
    		temp=operat.top();
    		if(temp=="-")
    		{
    			j=num.top();
    			num.pop();
    			k=num.top();
    			num.pop();
    			i=k-j;
    			num.push(i);
    			operat.pop();
    		}
    		else if(temp=="+")
    		{
    			j=num.top();
    			num.pop();
    			k=num.top();
    			num.pop();
    			i=j+k;
    			num.push(i);
    			operat.pop();
    		}
    		else if(temp=="*")
    		{
    			j=num.top();
    			num.pop();
    			k=num.top();
    			num.pop();
    			i=j*k;
    			num.push(i);
    			operat.pop();
    		}
    		else if(temp=="/")
    		{
    			j=num.top();
    			num.pop();
    			k=num.top();
    			num.pop();
    			i=k/j;
    			num.push(i);
    			operat.pop();
    		}
    		else
    		{
    			stringstream stream;
    			stream<<temp;
    			stream>>i;
    			num.push(i);
    			operat.pop();
    		}
    	}
    	
    	double result=0;                                                          //使result等于计算出的结果并且return出去 
    	result=num.top();
    	num.pop();
    	return result;
    }
    
    

    main 函数

    #include <iostream>
    #include <stdio.h> 
    #include <string.h>
    #include<queue>
    #include"Scan.h"
    #include"Print.h"
    #include"Calculation.h"
    using namespace std;
    
    int main(int argc,char *argv[])
    {
    	Scan get;                                                                     //定义scan类 
    	Print output;                                                                 //定义print类,但是这里没什么用。。。。 
    	Calculation cal;                                                              //定义calculation类,用于计算结果 
    	string input,_input;                                                          //定义一个字符串用来存储输入要计算的式子  
    	cin>>input;
        if(input=="-a")                                                               //如果有输入-a的话就得输出整个式子 
    	{ 
    	    cin >>_input;                                                             /*如果不是-a的话既不必在输入,因为input就已经是要计算的式子了,
    		                                                                          如果是-a则需要再输入要计算的式子 */ 
    	    cout<<_input;                                                             // 输出式子 
    		cout<<"= ";                                                               //格式要求
    		get.ToStringQueue(_input);                                                
    	}
    	else
    	{
    	    get.ToStringQueue(input);                                                /*把输入的input放入Scan类的函数进行计算,把计算后的值赋予
    		                                                                           Scan的成员 outputqueue*/
    	}                                                  
        if(get.outputqueue.front()=="ERROR")                                         //看是否输入的式子是有问题的,如果有问题就输出error 
        {
        	cout<<"ERROR"<<endl;
    	}
    	else
    	{
    		cout<<cal.Calculate(get.outputqueue)<<endl;                              //输出结果 
    	}
    	return 0;
    }
    
    

    5、测试数据的结果

    更新的结果(因为发现之前的-(-(1+1)+2)是算不出的。。。。。没考虑到括号内最前面是符号的情况)

    6、这次的收获

    • 明白了 前缀 中缀 后缀 的思路

    • 知道了sstream的使用方法(将字符串类型转化成为其他int,double子类的类型)

    • stack和queue的使用方法(明白区别,queue是先进先出,stack是后进先出)

    7、参考文件(看了很多,真正用到的就这些)

    (1).命令行,main函数传递参数:
    http://www.cnblogs.com/avril/archive/2010/03/22/1691477.html

    (2).前缀 后缀 中缀(核心思路):
    http://m.blog.csdn.net/article/details?id=6763722

    (3).stack和queue的使用:
    http://www.cnblogs.com/mfryf/archive/2012/08/09/2629992.html

    (4).sstream的使用(将字符串转化为别的类型):
    http://blog.163.com/zhuandi_h/blog/static/180270288201291710222975/

    8、总结

    一路上磕磕碰碰,但也是圆满完成(应该圆满了吧。。。。。),一路上少不了同学的帮助,一起讨论,也是一种乐趣,每一次的成功都会让你觉得之前的努力是值得的,就像我一开始以为一点小错误一直弄的程序无法运行,但是当我修改后,输入1+1这样简单的式子时候,结果是2,我就十分开心,哪怕是简单的等于2,我也知道我基本是成功的,就算后面还有点小问题,但最难的一坑已经迈过去了,而这次我想的也算齐全,从而我的代码在运行出1+1=2之后再试了几个结果都没什么错,就是后面碰到的一个,也就是前文所提的红色部分,那里被卡住了,但总的来说也是完美(可能还是有哪里是有问题的,看了我代码的人也可以帮我看看,是不是还有哪里有错误,先谢谢啦)。做出来还是很开心的,敲代码的过程或许是十分枯燥无味的,但是你做出点什么的时候,那种喜悦是其他东西给不了你的,也许这也是程序员能够坚持下来的原因吧。(当然我的代码中还是有很多地方可以简化的,比如定义函数来重复操作那些重复的地方)。这次也明白了博客的重要性,因为很多的学习文件都是从他人博客学来的,这让之前一直没用过博客的我渐渐爱上博客了。。

  • 相关阅读:
    Windows Server 2008搭建AD域控服务器
    远程桌面出现CredSSP解决方案
    破解Excel工作表保护,清除所有密码并获取密码
    Windows Server 2008 R2 搭建NTP时间服务器
    VMware Tools
    windows常用运行命令
    无线AP与AC详解
    单臂路由
    ACL控制指定IP访问限制
    Linux下安装VMware
  • 原文地址:https://www.cnblogs.com/zxlmhh/p/5379181.html
Copyright © 2011-2022 走看看