• 课程第六次作业


    课程第六次作业

    题目要求;

    • 本次作业要求将四则运算的核心部分采取栈的知识进行解决。即表达式生成的合法性检验、表达式结果计算。
    • 学习C++界面编程,可以学QT、MFC或者VS,选择其一即可,用博客记录学习到的知识以及心得体会。

    界面的不足之处:

    界面没有实现可以下一题的操作,没有锁定算式不能被操作,所以容易被误操作。使输出答案。

    学习链接

    git链接

    界面展示:


    代码展示:

    
    void CMFCApplication2Dlg::OnBnClickedButton1()
    {
    	UpdateData();
    	//expression ;窗口添加的变量
    	Problem p; 
    	tmp = p.generateExpression();
    	expression = tmp.c_str();//将string转变为Cstring	
    	UpdateData(false);
    }
    
    
    void CMFCApplication2Dlg::OnBnClickedButton2()
    {
    	UpdateData();
    	Problem p;
    	rightanswer = p.calculateResult(tmp);//tmp为全局变量实现题目的传入
    	if (answer == rightanswer)//answer为用户在界面输入的答案(窗口添加的变量),rightanswer为正确的答案
    	{
    		correctnum++;//给窗口添加的变量(正确的题目个数)
    	}
    	else
    		wrongnum++;//错误的答案
    	UpdateData(false);
    }
    

    核心算法流程图展示:

    生成算法:

    计算算法:

    生成算式部分

    //生成算式部分----------------------------------------------------------------------
    	int Randomvalue::randomNumber()//用于随机生成数字
    	{
    		return num[rand() % num.size()];
    	}
    	char Randomvalue::randomOperation()//用于随机生成运算符
    	{
    		return sign[rand() % sign.size()];
    	}
    
    	template<typename T>//模板
    	string CreatExpresstion::Tostring(T i)
    	{
    		stringstream ss;
    		string s;
    		ss << i;
    		ss >> s;
    		return s;
    	}
    
    	void CreatExpresstion::generateExpression()//用于生成运算式
    	{
    		expression = Tostring(R.randomNumber()) + Tostring(R.randomOperation()) + Tostring(R.randomNumber());//利用Tostring函数
    		int len = rand() % 5 + 2;
    		for (int i = 0; i < len; i++)//add '(' and ')'
    		{
    			int rdnum = rand() % 10 + 1;
    			if (rdnum<2)// 加左边 加括号
    			{
    				expression = Tostring(R.randomNumber()) + Tostring(R.randomOperation()) + "(" + Tostring(expression) + ")";//连接
    			}
    			else if (rdnum>8)// 加右边 加括号
    			{
    				expression = "(" + Tostring(expression) + ")" + Tostring(R.randomOperation()) + Tostring(R.randomNumber());
    			}
    			else if (rdnum<4)// 加左边 不加括号
    			{
    				expression = Tostring(R.randomNumber()) + Tostring(R.randomOperation()) + Tostring(expression);
    			}
    			else if (rdnum>6)// 加右边 不加括号
    			{
    				expression = Tostring(expression) + Tostring(R.randomOperation()) + Tostring(R.randomNumber());
    			}
    			// 不加
    		}
    		cout << expression << " = ";//输出算式
    		F.writeFile(out_file_name,expression);//写入文件中
    		F.writeFile(out_file_name," = ");
    		//myfile << expression << " = ";
    		answer = calculateResult();
    	}
    

    算式计算部分:

    unordered_map< char, unordered_map < char, char > > Priorities;
    
    void InitPriorities()//优先级代码
    	{
    		Priorities['+']['-'] = '>';
    		Priorities['+']['+'] = '>';
    		Priorities['+']['*'] = '<';
    		Priorities['+']['/'] = '<';
    		Priorities['+']['('] = '<';
    		Priorities['+'][')'] = '>';//右括号优先级最低
    
    		Priorities['-']['-'] = '>';
    		Priorities['-']['+'] = '>';
    		Priorities['-']['*'] = '<';
    		Priorities['-']['/'] = '<';
    		Priorities['-']['('] = '<';
    		Priorities['-'][')'] = '>';
    
    		Priorities['*']['-'] = '>';
    		Priorities['*']['+'] = '>';
    		Priorities['*']['*'] = '>';
    		Priorities['*']['/'] = '>';
    		Priorities['*']['('] = '<';
    		Priorities['*'][')'] = '>';
    
    		Priorities['/']['-'] = '>';
    		Priorities['/']['+'] = '>';
    		Priorities['/']['*'] = '>';
    		Priorities['/']['/'] = '>';
    		Priorities['/']['('] = '<';
    		Priorities['/'][')'] = '>';
    
    		Priorities['(']['+'] = '<';
    		Priorities['(']['-'] = '<';
    		Priorities['(']['*'] = '<';
    		Priorities['(']['/'] = '<';
    		Priorities['(']['('] = '<';
    		Priorities['('][')'] = '=';
    	}
    
    
    //算式计算部分----------------------------------------------------------------------
    	float CreatExpresstion::calculateResult()
    	{
    		vector<float> Operands;
    		vector<char> Operators;
    		float OperandTemp = 0;
    		char LastOperator = 0;
    
    		for (int i = 0; i < expression.size(); i++)
    		{
    			char ch = expression[i];//获取分解算式
    			if ('0' <= ch && ch <= '9')//如果为运算数
    			{
    				OperandTemp = OperandTemp * 10 + ch - '0';
    			}
    			else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')')
    			{
    				if (ch != '(' && LastOperator != ')')
    				{
    					Operands.push_back(OperandTemp);//压入运算数栈中
    					OperandTemp = 0;
    				}
    				char Opt2 = ch;
    				for (; Operators.size() > 0;)//不为空继续计算
    				{
    					char Opt1 = Operators.back();
    					char CompareRet = Priorities[Opt1][Opt2];//利用运算符优先级
    					if (CompareRet == '>')//如果优先级为大于
    					{
    						float Operand2 = Operands.back();//获取运算数栈顶元素
    						Operands.pop_back();//冒掉栈顶元素
    						float Operand1 = Operands.back();//获取第二个运算数栈顶元素
    						Operands.pop_back();//冒掉运算数
    						Operators.pop_back();//冒掉运算符
    						float Ret = caculate(Operand1, Operand2, Opt1);//调用计算函数
    						Operands.push_back(Ret);//将计算结果压入栈中以便继续计算
    					}
    					else if (CompareRet == '<')//如果优先级为小于则跳过
    					{
    						break;
    					}
    					else if (CompareRet == '=')//如果优先级相等
    					{
    						Operators.pop_back();
    						break;
    					}
    				}
    				if (Opt2 != ')')
    				{
    					Operators.push_back(Opt2);
    				}
    				LastOperator = Opt2;
    			}
    		}
    		if (LastOperator != ')')
    		{
    			Operands.push_back(OperandTemp);
    		}
    		for (; Operators.size() > 0;)//如果运算符栈不为空继续
    		{
    			float Operand2 = Operands.back();
    			Operands.pop_back();
    			float Operand1 = Operands.back();
    			Operands.pop_back();
    			char Opt = Operators.back();
    			Operators.pop_back();
    			float Ret = caculate(Operand1, Operand2, Opt);
    			Operands.push_back(Ret);
    		}
    		return (float)((int)(Operands.back() * 100)) / 100;//将计算结果返回为保留两位小数
    	}
    
    	float CreatExpresstion::caculate(float Operand1, float Operand2, char Operator)
    	{
    		if (Operator == '+') return Operand1 + Operand2;
    		if (Operator == '-') return Operand1 - Operand2;
    		if (Operator == '*') return Operand1 * Operand2;
    		if (Operator == '/') return Operand1 / Operand2;
    	}
    	//----------------------------------------------------------------------------------
    
    

    操作界面展示:

    本次作业的心得:

    本次作业实现了栈以及生成算式的核心算法,栈是一种重要的思想,曾经以为很难的计算过程可以利用栈来精巧的解决,而这些是想不到的,在查阅计算器计算过程中发现了这一点,在界面学习的过程中第一次觉得更像在写程序的感觉,界面使这一应用更趋向完整性、有使用价值,在今后的学习中会利用课余的时间学习更加高深精致的界面制作。

  • 相关阅读:
    图片滚动懒加载用jquery-lazyload 与手动Jquery 写
    穿梭框(filter过滤方法,sort排序 v-model)
    选择添加好友(包含 去重,删除splice 等) v-show(解决显示隐藏闪动问题)
    求数组中最小的数值(结合apply() call())
    Vue
    js递归
    使用kdf 元素来接收键盘的输入指令
    编辑滚动条样式
    【IntelliJ IDEA】Debug调试的使用记录
    福利:IntelliJ IDEA 破解激活教程
  • 原文地址:https://www.cnblogs.com/mercuialC/p/6925902.html
Copyright © 2020-2023  润新知