课程第六次作业
题目要求;
- 本次作业要求将四则运算的核心部分采取栈的知识进行解决。即表达式生成的合法性检验、表达式结果计算。
学习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; } //----------------------------------------------------------------------------------
操作界面展示:
本次作业的心得:
本次作业实现了栈以及生成算式的核心算法,栈是一种重要的思想,曾经以为很难的计算过程可以利用栈来精巧的解决,而这些是想不到的,在查阅计算器计算过程中发现了这一点,在界面学习的过程中第一次觉得更像在写程序的感觉,界面使这一应用更趋向完整性、有使用价值,在今后的学习中会利用课余的时间学习更加高深精致的界面制作。
来源:https://www.cnblogs.com/mercuialC/p/6925902.html