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