要求0:html
做业地址:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2266
git
要求1:算法
git仓库地址:https://git.coding.net/wangc556/f4.git
编程
要求2:函数
结对同窗博客地址:https://www.cnblogs.com/wangcwcgnaw/p/9926468.html 性能
结对同窗名字:王储 2016011925学习
解题思路:编码
根据王储同窗的提示,四则运算求值必定要用到逆波兰表达式,因此我百度搜了一下逆波兰表达式的做用和用法。spa
将一个普通的中序表达式转换为逆波兰表达式的通常算法是:.net
(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,若是该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)若是不是数字,该字符则是运算符,此时需比较优先关系。
作法以下:将该字符与运算符栈顶的运算符的优先关系相比较。若是,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。假若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。
(5)重复上述操做(3)-(4)直至扫描完整个简单算术表达式,肯定全部字符都获得正确处理,咱们即可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
以后的每一个功能在使用逆波兰表达式的基础上又作了一些细节的改动。
每一个功能重、难点:
功能一:实现运算数为整数的不含小括号的四则运算,运算符具备优先级,对优先级进行规定。
功能二:在功能一的基础上支持了小括号,括号参与运算后是考虑括号的匹配和生成顺序,定义temp为未匹配的左括号数来解决括号匹配问题。同时考虑运算数据为浮点型,判断结果为无限小数仍是有限小数很困难。
功能三:生成的四则运算表达式是不重复的而且工整输出。由于表达式重复的状况太多因此我认为这是一大难点,也是咱们不太知道如何解决的。
1.进行题目数、功能、文件路径等变量定义
int main(int argc,char* argv[]){ string ss;//题目数的字符串 int qwq=0;//功能 string path;//输出的文件路径 for(int i=1;i<argc;++i){ string str=argv[i]; if(str=="-n"||str=="-c"){ ss=argv[i+1]; if(str=="-n") qwq=1; else qwq=2; } if(str=="-f") qwq=3,path=argv[i+1]; } int num=0,l,cnt=0;//num问题数,cnt回答正确数 //把问题数字符串转化为整数 l=ss.size(); for(int i=0;i<l;++i){ num*=10; num+=ss[i]-'0'; } //每次生成的随机数都不一样 srand((int)time(0));
2.生成运算式,使用rand()函数,功能一随机生成1-10的整数,功能2、三生成0.01-10.00的浮点数
string s="";//生成的运算式的字符串 int temp=0;//未匹配的左括号数 //生成运算式 if(qwq==1){ for(int i=1;i<=4;++i){ if(i==1){ int r1=rand2(1,10); //整数转字符串 stringstream ssss; ssss<<r1; string t; ssss>>t; s+=t; } else{ int r1=rand2(1,5); if(r1==1) s+="+"; if(r1==2) s+="-"; if(r1==3) s+="*"; if(r1==4) s+="/"; int r2=rand2(1,10); stringstream ssss; ssss<<r2; string t; ssss>>t; s+=t; } } }
定义temp为当前位置未被匹配的左括号数量,在以后的位置以temp为上界,将未匹配的的括号进行匹配,保证括号合法。
else{ for(int i=1;i<=5;++i){ if(i==1){ int r1=rand2(0,2); for(int i=0;i<r1;++i) s+="("; temp+=r1;//temp:未匹配的左括号数 double r2=rand1(1,1000); stringstream ssss; ssss<<r2; string t; ssss>>t; s+=t; } else if(i==5){ for(int i=0;i<temp;++i) s+=")"; temp=0; } else{ int r1; //生成右括号 if(temp){ r1=rand2(0,temp); for(int i=0;i<r1;++i) s+=")"; temp-=r1; } int r2=rand2(1,5); if(r2==1) s+="+"; if(r2==2) s+="-"; if(r2==3) s+="*"; if(r2==4) s+="/"; //生成左括号 r1=rand2(0,2); for(int i=0;i<r1;++i) s+="("; temp+=r1; double r3=rand1(1,1000); stringstream ssss; ssss<<r3; string t; ssss>>t; s+=t; } } }
3.定义两个栈运算符栈和数字栈 应用逆波兰表达式
stack<double>sv; stack<char>sp; char c; int k=0,flag=1; double x,y; sp.push('\0');
//逆波兰表达式实现 c=s[k]; while(flag){ if(c>='0'&&c<='9'||c=='.') sv.push(to_num(s,k)); else if(c=='\0'&&sp.top()=='\0') flag=0; else if(c=='('||(level(c)>level(sp.top()))){ sp.push(c); k++; } else if(c==')'&&sp.top()=='('){ sp.pop(); k++; } else if(level(c)<=level(sp.top())){ x=sv.top(); sv.pop(); if(sv.empty()) y=0; else{ y=sv.top(); sv.pop(); } c=sp.top(); sp.pop(); switch(c){ case '+':y = x+y; break; case '-':y = y-x; break; case '*':y = x*y; break; case '/':y = y/x; break; } sv.push(y); } c=s[k]; } double ans=sv.top();//运算式的值
4.在功能三上咱们不太知道如何避免重复,因此采用map映射来存储结果判断结果是否出现过,以保证表达式不一样
//四舍五入 int dd=ans*10000; if(dd%10>=5) dd=dd-dd%10+10; else dd=dd-dd%10; ans=dd/10000.0; dd/=10000.0; if(mp[ans]){ j--; continue; } else mp[ans]++;
编程体会:
因为本身的编程能力不强,因此我找了编程能力较强的王储同窗做为队友,但愿能够在结对编程的过程当中学习到一些知识,提升本身。谢谢王储同窗对我提出的疑问耐心解答,对我不会的知识点进行讲解,我以为本身在这个过程当中学到了不少有了一些提升。
我在结对编程以前读了《构建之法》第四章两人合做这一部分知识,邹欣老师说,在结对编程中,任何一段代码都至少被两双眼睛看过,被两个脑壳思考过,结对编程避免了“个人代码”仍是“他的代码”的问题,使而整个代码的责任不属于某我的,而是属于两我的,进而属于整个团队。还有结对编程中驾驶员和领航员的角色要常常互换,避免长时间紧张工做而致使的观察力和判断力降低。因此我认为结对编程仍是颇有必要的,对于一个好性能的软件或者程序,我感受结对编程是不可缺乏的。
3项在编码、争论等活动中花费时间较长,给你较大收获的事件:
(1)定义两个栈 使用逆波兰表达式
(2)括号匹配 判断数据是否有限/无限循环并四舍五入保留三位小数
(3)如何判断重复的表达式并再也不计算重复的式子
收获:在此过程当中学到了不少编程思想,在队友的讲解下感受方法很巧妙。