要求0:
作业地址:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2266
要求1:
git地址: https://git.coding.net/Jingr98/f4.git
要求2:
1.结对编程同学的博客地址&姓名:https://www.cnblogs.com/Jingr/p/9924521.html 井冉
2.解题思路:
当初看到四则运算这个题目时,第一想法是先解决计算表达式这一块,再来增加生成表达式的功能,大致形成计算表达式(满足功能1)-->计算表达式(满足功能2和功能3)-->随机生成表达式的流程思路。于是先在网上查找了四则运算计算这一块的内容,发现大多会使用中缀表达式与后缀表达式来完成,并采用双栈(即操作数一个栈,运算符一个栈),从这篇博客我还了解到挺多的(https://blog.csdn.net/that163/article/details/7558268),代码简短易懂。其次就是随机生成四则运算题目,在网上查阅了很多博主写的代码,参考了他们的随机生成算式的思路如下:
- 随机生成一个数字,代表着生成表达式中操作数的个数。
- 循环生成一个数字,将其输出,然后等概率生成‘+’‘-’‘*’‘/’中的一个跟在该数字后面,输出。
- 以一定概率生成左括号,若生成了左括号则输出,并进行计数标志当前共有多少个未完成匹配的左括号。
- 若当前有未完成匹配的左括号,则在生成一个数字后,生成一个操作符前,以一定的概率生成右括号。
- 在生成完毕后,生成最后一个数并将为匹配的左括号予以匹配。
附上博客地址,希望对大家有用(https://www.cnblogs.com/fanfan-blogs/p/5246469.html)。
3.重点/难点
1)功能1:支持整数和不含括号的四则运算且表达式可以重复。
功能1只需要计算整数,所以唯一的难点是输出结果时的判断。当时没有读清题目,考虑不仔细,简单的判断若为整数,则原样输出,否则,保留3位小数,但发现会存在有可以被整除的小数,得到的结果可能是类似2.5,19.36等这样的形式,这时保留3位小数就会输出结果冗余。所以又改了思路,判断小数点后面的位数,如果位数超过3位,则保留3位输出,否则原样输出。附上判断小数位数代码。
函数point():判断小数点后面的位数是否超过3
/** *函数名:point() *函数功能:判断小数点后面的位数是否超过3 *param:double num */ int point(double num) { int i,f = 0; num *= 1000; if(num - (int)num > eps) f = 1; return f; }
2)功能2:支持小数和含小括号的四则运算且表达式可以重复。
功能2涉及到小数和小括号的运算,同样也涉及到了结果的输出以及和用户的结果进行对比,判断是否正确。由于要求只需保留到3位小数,故设置eps=1e-4,当用户结果与正确答案相差小于eps时,则判定回答正确。其次,是由于小括号的加入,所以还涉及到了更进一步的优先级计算,于是直接设置了判断优先级的函数,给6种运算符赋予优先级。最后就是由于小括号的加入,需要随机生成小括号,下附部分代码:
//小括号的随机生成 if( n < 3 && i < 6 && i > 0 ){ s += "("; ans1++; } s += tmp; if( n > 6 && i > 0 && i < 6){ if( ans1 > 0 ) ans1--; else ans2++; s += ")"; } } else { int n = rand() % 4; s += op[n]; } } sort( a , a + 4 ); pdd current = mk( a[0] , a[1] , a[2] , a[3] ); if( stPdd.find(current) != stPdd.end() ){ tmp++; return 1; } stPdd.insert( current ); string lft , rht; //保证小括号成对出现 for(int i = 0 ; i < ans2 ; i++ ) lft += "("; for(int i = 0 ; i < ans1 ; i++ ) rht += ")"; s = lft + s + rht;
3)功能3:表达式不重复且输出结果显示在控制台,且将控制台显示的结果输出到指定位置的txt文件中。
功能3其实就是在功能2的基础上增加表达式不重复且将结果输出到指定文件中的功能。在使生成的表达式不重复上,我感觉还是挺难的,因为你需要判断交换律、结合律、分配律等导致的重复的情况,比较复杂,所以这个地方是参考了别人的代码,然后是将控制台结果输出到txt文件里,在这里运用到了C++的ofstream,
ofstream fout( "d:\mytest.txt" );
fout << "Learning C++ is very useful."<< endl;
搜索到了这样一篇博客,详细的讲解了ofstream与ifstream的用法(https://www.cnblogs.com/batman425/p/3179520.html)。
4)解决计算表达式的功能:利用双栈将中缀表达式转换成后缀表达式,遍历后缀表达式得到结果。此处通过双栈,分离开操作数与运算符,简化了计算,方便操作与判断。下附解决代码:
/** *函数名:work() *函数功能:利用双栈将中缀表达式转换成后缀表达式,遍历后缀表达式得到结果 *param:string s */ double work(string s ) { stack<double> sNum; //存储操作数的栈 stack<char> sOp; //存储运算符的栈 int i = 0, flag = 1; char c; double x, y; sOp.push('