• 第四次程序设计作业 C++计算器计算及命令行的使用 前缀表达式方法实现


    关键词:前缀中缀后缀表达式 波兰式 命令行

    myGithub

    一.前言

    很有意思的开发和学习经历,从刚刚开始看到作业思考半天到现在的Debug过程,对我来说都或多或少有所提升。
    也许这个时候自己挺迷茫的,想未来的路在哪里。一转眼,自己就走出去了很远,白驹过隙,时光荏苒。

    二.本次作业的步骤梳理

    • 1.Windows系统下的cmd命令行操作
    • 2.输入字符串input过程中的特判负号
    • 3.计算过程中符号优先级的判断
    • 4.输入错误的判断
    • 5.总结与反馈

    这里我的解决步骤是:2->4->3->1->5。本篇博客主要介绍第3步和第1步。

    三.计算的实现

    代码:

    calculation.h

    //==============================//
    //文件名称:calculation.h       
    //作者:031502209               
    //更新时间:2016/4/7            
    //博客:qq952693358             
    //==============================//
    #ifndef CALCULATION_H
    #define CALCULATION_H
    #include<stack>
    #include<queue>
    #include<iostream>
    #include<stdlib.h>
    #include<string>
    using namespace std;
    
    //===============================//
    //class:Calculation              
    //包含:执行计算函数carryout     
    //函数类型:int                  
    //===============================//
    class Calculation
    {
    
    	public:
            int carryout(queue<string> que);   
    };
    
    #endif // CALCULATION_H
    

    calculation.cpp

    //==============================//
    //代码主体部分:calculation      
    //文件名称:calculation.cpp     
    //作者:031502209               
    //更新时间:2016/4/7            
    //博客:qq952693358            
    //==============================//
    
    //==================================//
    //说明:该部分分为两大块            
    //1.把原来的式子转换成为前缀表达式  
    //2.前缀表达式的计算                
    //==================================//
    #include "calculation.h"
    #include<stack>
    #include<queue>
    #include<iostream>
    #include<stdlib.h>
    #include<string>
    #include<sstream>
    
    //======priority=======//
    //说明:用于判断优先级 
    //=====================// 
    int priority(string s)
    {
        if(s=="(" || s== ")")return 0;
    	if(s=="+" || s=="-")return 1;
    	if(s=="*" || s=="/")return 2;
    	if(s=="#")return -1;
    }
    
    //======calculate======//
    //说明:用于计算      
    //=====================// 
    int calculate(string s,int a,int b)//double
    {	
    	if(s=="+")return b+a;
    	if(s=="-")return b-a;
    	if(s=="*")return b*a;
    	
    	if(s=="/" && a!=0)return b/a;
    	else return 0;
    }
    //========代码主体========// 
    int Calculation::carryout(queue<string> que)
    {
    	//判断是否出错 
    	if(que.empty())
    	{
    		cout<<"error"<<endl;
    		return 0;
    	}
    	
    	stack<string> sign1,sign2;
    	stack<string> signstore;//倒序 
    	
    	string s;
    	string que_s;
    	string sign1_top;
    	
    	//==========================//
    	//从'='开始从右向左遍历      
    	//所以用一个栈signstore实现 
    	//==========================//
    	while(!que.empty())
    	{
    		signstore.push(que.front());
    		que.pop();
    	}
    	
    //-------------------------BEGIN-------------------------//	
        
        //======部分1======//
    	//转换为前缀表达式 
    	//=================// 
    	while(!signstore.empty())
    	{
    		s=signstore.top();
    	    signstore.pop();
    		
    		if(s=="=")continue;
    		if(s=="+" || s=="-" || s=="*" || s=="/" || s=="(" || s==")")
    		{
    			//=============说明=============// 
    			//如果存在以下情况:             
    			//(1)s的优先级大于sign1栈顶元素 
    			//(2)s==")"                     
    			//(3)sign1为空栈                
    			//则:s直接push进sign1          
    			//==============================//
    			
    			//sign1为空栈  
    			if(sign1.empty())
    			{
    				sign1.push(s);
    				
    				continue;
    			}
    			
    			//s==")"
    			if(s==")")
    			{
    				sign1.push(s);
    				
    				continue;
    			}
    			
    			//=============说明=============// 
    			//如果遇到左括号:             
    			//把sign1里面的字符push进sign2  
    			//直至遇见右括号               
    			//==============================//
    			if(s=="(")
    			{
    			    while(sign1.top()!=")")
    			    {
    			    	sign2.push(sign1.top());
    			    	
    			    	sign1.pop();
    			    }
    				sign1.pop();//右括号出栈 
    				continue;
    			}
    			
    			//s的优先级大于sign1栈顶元素 //
    			if(priority(s) > priority(sign1.top()))
    			{
    				sign1.push(s);
    			    
    				continue;
    			}
    		    
    			//s的优先级小于sign1栈顶元素//
    			
    			//==============说明===============//
    			//当遇到s的优先级小于栈顶元素时   
    			//把sign1里面的字符从栈顶          
    			// push进sign2                    
    			//直到栈顶元素优先级大于s          
    			//=================================// 
    			else if(priority(s) < priority(sign1.top()))
    			{
    				while(priority(s) < priority(sign1.top()))
    				{
    					sign1_top=sign1.top();
    					
    				    sign1.pop();
    				    sign2.push(sign1_top);
    				}
    				sign1.push(s);
    				continue;
    			}
    			else //优先级相同 且非"("括号")"直接入sign1 
    			{
    				if(s=="+" || s=="-" || s=="*" || s=="/")
    				sign1.push(s);
    			}
    		}
    		else //如果是数字的话 push进sign2 
    		{
    			sign2.push(s);
    			continue;
    		}
    	}
    	
    	//将sign1中剩余的部分按顺序push进sign2 
    	while(!sign1.empty())
    	{
    		sign2.push(sign1.top());
    		sign1.pop();
    	}
    	
    	//转换为前缀表达式 完成 
    	
    //-------------------------END-------------------------//	
    	
    	//========部分2========// 
    	//计算前缀表达式       
    	//=====================//
    	
    	//sign2逆序存放->sign_2 
    	stack<string> sign_2;
    	while(!sign2.empty())
    	{
    		sign_2.push(sign2.top());
    		
    		sign2.pop();
    	}
    	
    	//使用stringstream 把字符串转换为数字 
    	stringstream stream;
    	int number;
    	stack<int> numberstore;//存储数字的栈 
    	string s2;
    	
    	//计算部分 
    	while(!sign_2.empty())
    	{
    		s2=sign_2.top();
    		sign_2.pop();
    		
    		//遇到运算符 提取出numberstore栈顶两个元素进行计算
    		//结果push进numberstore 
    		if(s2=="+" || s2=="-" || s2=="*" || s2=="/")
    		{
    			int number1;
    			number1=numberstore.top();
    			numberstore.pop();
    			
    			int number2;
    			number2=numberstore.top();
    			numberstore.pop();
    			
    			int cal_number;
    			cal_number=calculate(s2,number2,number1);
    			
    			numberstore.push(cal_number);
    			
    			continue;
    		}
    		else //遇到操作数 转换为数字之后入栈 
    		{
    			stream.str(s2);
    			stream>>number;
    			
    			numberstore.push(number);
    			stream.clear();
    			
    			continue;
    		}
    	}
    	
    	int value=0;
    	
    	value=numberstore.top();//栈顶元素即最终结果 
    	 
    	return value;
    }
    

    四.CMD命令行

    以下是主函数的写法:

    #include "calculation.h"
    #include "calculator.h"
    #include "print.h"
    
    #include<string>
    #include<string.h>
    #include<queue>
    #include<stdlib.h>
    #include<iostream>
    using namespace std;
    int bitjudge=0;
    
    int main(int argc,char*argv[])    //不通过命令行输入时通过Input类来输入 
    {
        queue<string> que; // type:queue<string>
        
    	Scan Sc;    // Define a "Scan" object:"Sc".
        Print Put;  // Define a "Print" object "Put".
        Calculation Ca; // Define a "Calculation" object "Ca".
        
        string str=argv[argc-1];  
        
        if(strcmp(argv[1],"-a")==0) //判断是否有输入'-a' 
        {
        	que.push(str);
        	Put.pout(que);    // printf que.
        }
        
        while(!que.empty())que.pop();  // 清空que 
         
    	que=Sc.ToStringQueue(argv[argc-1]);
        
        cout<<Ca.carryout(que)<<endl;
        return 0;
    }
    
    

    实现效果如下:

    五.不足的地方(已做出改进)

    我从我原来的代码进行了改进,在原来的要求下,我输出了整个式子,并且在之后进行了错误判断:<1>输入的式子左右括号匹配判断 <2>输入的数超过十位
    但是如果使用命令行的话,在输入'-a'的时候会进行判断,但是没有'-a'的时候就会跳过(判断在调用的print.cpp内)。还有一个就是小数的处理。
    这是美中不足的地方。

    今天改进了一下:实现报错功能,处理了小数的情况,对主函数进行了修改。

    六.数据处理(举两个例子):

    1.(-3+(9-((10-8)+(9-8*6/2+3)-10*10))*(8-(1+8/4)+2))=830
    2.(3+(-1+2*8)*2)+(9-8*1)=34

    七.总结:

    经过这些天的努力和尝试,把之前想象中异常困难的任务完成了。在我之前的代码上依照要求进一步的开发,学习了CMD命令行和sstream的使用,总体上对这些天的经历感到满意。但是我也看到了自己的不足和缺点,主要是:
    1.自己的知识储备相对浅薄,仍然需要扩宽知识面,不断学习新的知识。
    2.编程能力仍然需要提升。
    3.提高阅读代码的能力,多去思索别人的想法和做法。
    希望接下来的自己再接再厉,坚持下去。

                                                                                                                      2016/4/9
    

    更新:关于参考网址。
    1.前后缀表达式 写的超赞。
    2.命令行

    更新:(2016/4/11) 解决了开头为负号的特殊情况

  • 相关阅读:
    关于 未能加载文件或程序集“ImageMagickNet”或它的某一个依赖项。试图加载格式不正确的程序 的解决办法
    Nhibernate中 ManyToOne 中lazy="proxy" 延迟不起作用的原因
    关于mysqlconnectornet6.3.4 MySqlDataAdapter 在空数据的情况下填充DataSet后tables[0] 找不到的问题
    JavaScript:constructor属性
    关于AspNetPager 采用URL分页时 执行两次绑定的解决办法
    WPF学习笔记(一)
    unity3d 屏幕坐标、鼠标位置、视口坐标和绘制GUI时使用的坐标
    FileUpLoad用法(二)上传文件到服务器的数据库
    ASP.Net 使用GridView模板删除一行的用法
    ASP.Net FileUpLoad 控件的用法(一)——上传到服务器文件夹下
  • 原文地址:https://www.cnblogs.com/qq952693358/p/5363041.html
Copyright © 2020-2023  润新知