四则运算03 结对开发

要求如下:

  1. 能够判断用户输入的答案是否正确。
  2. 能够处理四种运算的混合运算。连续的减法和除法,应遵守左结合的规定;连续除法要打括号,否则引起歧义。

代码如下:

1 #include <iostream>
  2 #include <iomanip>
  3 #include <fstream>
  4 #include <ctime>
  5 #include <cstdlib>
  6 #include <sstream>
  7 #include <string>
  8 #include <vector>
  9 #include <algorithm>
 10 #include <stack>
 11 #include <cctype>
 12 #include <cmath>
 13 using namespace std;
 14 bool checkResult(string exp,string result);
 15 string pri[7][7]={
 16     {">",">","<","<","<",">",">"},
 17     {">",">","<","<","<",">",">"},
 18     {">",">",">",">","<",">",">"},
 19     {">",">",">",">","<",">",">"},
 20     {"<","<","<","<","<","=",""},
 21     {">",">",">",">","",">",">"},
 22     {"<","<","<","<","<","","="}
 23 };
 24
 25 bool isTrueFraction(int numerator, int denominator)    //判断产生的分数是否是真分数
 26 {
 27     if(numerator >= denominator)
 28         return false;
 29
 30     for(int i = 2 ; i <= numerator ; i++)      //判断分数是否能够约分
 31     {
 32         if(numerator % i ==0 && denominator % i == 0)
 33             return false;
 34     }
 35
 36     return true;
 37 }
 38
 39 string getNum(int start = 0, int end = 100, bool isParentheses = false, int depth = 0)
 40 {
 41     int n = rand();
 42     if(isParentheses)      // 若带括号 则为 a op ( b op c ) 的形式 op为运算符
 43     {
 44         int num1 = rand() % (end - start + 1) + start;
 45         stringstream ss;
 46         ss << num1;
 47
 48         if(depth  < 9)     //控制递归层数,带括号的式子少于10个
 49         {
 50             string num2 = "( " + getNum(start, end, n % 2 == 0,depth + 1) + " )";
 51             return ss.str() +" , "+ num2;
 52         }
 53         else
 54         {
 55             string num2 = "( " + getNum(start, end, false) + " )";
 56             return ss.str() +" , "+ num2;
 57         }
 58     }else
 59     {
 60         if(n % 7 == 0)       //若随机数n是7的倍数,产生一个真分数和一个整数,否则为两个整数
 61         {
 62             int num1 = rand() % (end - start + 1) + start;
 63             int num2 = rand() % (end - start + 1) + start;
 64             int num3 = rand() % (end - start + 1) + start;
 65
 66             if(isTrueFraction(num1,num2))
 67             {
 68                 stringstream s1,s2,s3;   //将int转为string
 69                 s1<<num1;
 70                 s2<<num2;
 71                 s3<<num3;
 72                 return s1.str()+"/"+s2.str()+" , "+s3.str();
 73             }else
 74             {
 75                 return getNum(start,end);
 76             }
 77         }else
 78         {
 79             int num1 = rand() % (end - start + 1) + start;
 80             int num2 = rand() % (end - start + 1) + start;
 81             stringstream s1,s2;
 82             //string ss1,ss2;
 83             s1<<num1;
 84             s2<<num2;
 85             return s1.str()+" , "+s2.str();
 86         }
 87     }
 88
 89
 90 }
 91
 92 char getOperator(string num2 = "1", bool isMulandDiv = true)   // 默认第二个参数不为0,默认包括乘除法
 93 {
 94     char op[] = {‘+‘,‘-‘,‘*‘,‘/‘};
 95
 96     if(isMulandDiv)
 97     {
 98         if(num2 == "0") //避免除数为0
 99             return op[rand() % 3];
100         else
101             return op[rand() % 4];
102     }else
103     {
104         return op[rand() % 2];     //只包含加减
105     }
106 }
107
108 bool isDup(vector<string> &items, string item)    //若重复返回true,否则返回false
109 {
110     if(find(items.begin(),items.end(),item) == items.end())
111         return false;
112     else
113         return true;
114 }
115
116 bool isNegative(string num1, string num2, char op)      //判断两数加减的正负
117 {
118     stringstream ss1,ss2;
119     int n1,n2;
120     ss1 << num1;
121     ss1 >> n1;
122     ss2 << num2;
123     ss2 >> n2;
124     if(op == ‘-‘)
125     {
126         if(n1 < n2)
127         {
128             return true;
129         }else
130         {
131             return false;
132         }
133     }else
134     {
135         if(n1 + n2 < 0)
136             return true;
137         else
138             return false;
139     }
140
141 }
142
143 bool isRemainder(string num1, string num2)   //判断两数相除有无余数
144 {
145     stringstream ss1,ss2;
146     int n1,n2;
147     ss1 << num1;
148     ss1 >> n1;
149     ss2 << num2;
150     ss2 >> n2;
151
152     if(n1 % n2 == 0)
153         return false;
154     else
155         return true;
156 }
157
158 void printAndCheck(vector<string> &items, bool isCmd)
159 {
160     vector<string>::iterator it = items.begin();
161     string answer;
162     if(isCmd)  //答案是分数或整数
163     {
164
165         for(;it != items.end(); it++)
166         {
167             cout << (*it) <<endl;
168             cout << "answer:";
169             cin >> answer;
170             if(checkResult((*it),answer))
171             {
172                 cout << "Bingo!!!" <<endl;
173             }else
174             {
175                 cout << "Oh ,stupid guy!!" <<endl;
176             }
177         }
178
179         cout << "Problems finished!" << endl;
180     }else
181     {
182         ofstream of("problems.txt");
183         if(!of)
184             exit(1);
185
186         for(;it != items.end() ; it++)
187             of<<*it <<endl;
188
189         of.close();
190     }
191
192
193 }
194 int getOpersNum(string op)    //返回运算符编号,用于比较优先级 +-*/()# 对应 0123456
195 {
196     if(op == "+")
197     {
198         return 0;
199     }else if(op == "-")
200     {
201         return 1;
202     }else if(op == "*")
203     {
204         return 2;
205     }else if(op == "/")
206     {
207         return 3;
208     }else if(op == "(")
209     {
210         return 4;
211     }else if(op == ")")
212     {
213         return 5;
214     }else if(op == "#")
215     {
216         return 6;
217     }else
218     {
219         cout << "Error!" << endl;
220         exit(1);
221     }
222 }
223
224 double calculate(double n1, double n2, string op)
225 {
226     if(op == "+")
227     {
228         return n1 + n2;
229     }else if(op == "-")
230     {
231         return n1 - n2;
232     }else if(op == "*")
233     {
234         return n1 * n2;
235     }else if(op == "/")
236     {
237         return n1 / n2;
238     }else
239     {
240         cout << "Error" <<endl;
241         exit(1);
242     }
243 }
244
245 bool checkResult(string exp,string result)
246 {
247     stack<string> ops;
248     stack<double> nums;
249     ops.push("#");
250     exp = exp + " #";    //加起始结束标识
251     int flag = -1;  //字符串扫描标识 标识" "的位置
252     while (!( exp[flag + 1] == ‘#‘ && ops.top() == "#"))  //当符号栈栈顶元素和扫描出的下一个元素不同时为#时
253     {
254         string str = exp.substr(flag + 1, exp.find(" ",flag + 1) - flag -1);
255         if(str != "+" && str != "-" && str != "*" && str != "/" && str != ")" && str != "(" && str != "#")    //不是运算符
256         {
257             if(str.find("/") == string::npos)   //str为整数的情况
258             {
259                 stringstream ss;
260                 double n;
261                 ss << str;
262                 ss >> n;
263                 nums.push(n);
264                 flag = exp.find(" ",flag + 1);
265             }else    //分数的情况
266             {
267                 stringstream ssNum,ssDen;
268                 double numerator,denominator;     //分子 分母
269                 ssNum << str.substr(0,str.find("/"));
270                 ssDen << str.substr(str.find("/") + 1);
271                 ssNum >> numerator;
272                 ssDen >> denominator;
273                 nums.push(numerator/denominator);  //以double型压栈
274                 flag = exp.find(" ",flag + 1);
275             }
276         }else   //str是运算符
277         {
278             if(pri[getOpersNum(ops.top())][getOpersNum(str)] == "<")
279             {
280                 ops.push(str);
281                 flag = exp.find(" ",flag + 1);
282             }else if(pri[getOpersNum(ops.top())][getOpersNum(str)] == ">")
283             {
284                 string op = ops.top();
285                 ops.pop();
286                 double num2 = nums.top();
287                 nums.pop();
288                 double num1 = nums.top();
289                 nums.pop();
290                 nums.push(calculate(num1,num2,op));
291             }else if (pri[getOpersNum(ops.top())][getOpersNum(str)] == "=")
292             {
293                 ops.pop();
294                 flag = exp.find(" ",flag + 1);
295             }else
296             {
297                 cout << "Error!!!";
298                 exit(1);
299             }
300         }
301     }
302     double res;
303     if(result.find("/") == string::npos)  //结果是整数
304     {
305         stringstream ss;
306         ss << result;
307         ss >>res;
308     }else  //结果是分数
309     {
310         stringstream ssNum,ssDen;
311         double numerator,denominator;     //分子 分母
312         ssNum << result.substr(0,result.find("/"));
313         ssDen << result.substr(result.find("/") + 1);
314         ssNum >> numerator;
315         ssDen >> denominator;
316         res = numerator/denominator;
317     }
318
319     if(fabs(nums.top() - res) < 1e-4)    //int,double,string多次转换可能结果有偏差,设置10的-4次方为阈值检验结果正确性
320     {
321         return true;
322     }else{
323         return false;
324     }
325 }
326
327 int main(int argc, char *argv[])
328 {
329     srand((int)time(0));    //设定时间种子
330     vector<string> items;   //将题目存在items中,用于判断是否重复和输出
331     int itemNum,tmp;  //题目数量
332     char ttmp;
333     bool isCmd;    //打印方式
334     bool isMulandDiv;     //是否有乘除法
335     bool isParentheses;  //是否带括号
336     int start,end;  //数值范围
337     bool isNeg;    //有无负数
338     bool isRem;    //有无余数
339     bool addFlag = false;  //添加标识
340
341     cout << "Please input the problem number:" << endl;       //定制题目数量、打印方式等
342     cin >> itemNum;
343     if(itemNum < 0 )
344     {
345         cout << "Error input!" <<endl;
346         exit(1);
347     }
348
349     cout << "Please input the display mode(0. screen 1.file)" <<endl;
350     cin >> tmp;
351     if(tmp == 0)
352     {
353         isCmd = true;
354     }else if(tmp == 1)
355     {
356         isCmd = false;
357     }else
358     {
359         cout << "Error input!" <<endl;
360         exit(1);
361     }
362
363     cout << "Include multiplication or division? (Y/N)" <<endl;
364     cin >>ttmp;
365     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
366     {
367         isMulandDiv = true;
368     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
369     {
370         isMulandDiv = false;
371     }else
372     {
373         cout << "Error!"<<endl;
374         exit(1);
375     }
376
377     cout << "Include parenthesses? (Y/N)" <<endl;
378     cin >>ttmp;
379     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
380     {
381         isParentheses = true;
382     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
383     {
384         isParentheses = false;
385     }else
386     {
387         cout << "Error input!"<<endl;
388         exit(1);
389     }
390
391     cout << "Please input the number range:(devide by a blank)" << endl;
392     cin >> start >> end ;
393     if(start > end)
394     {
395         swap(start, end);
396     }
397
398     cout << "Is additions and subtractions have negative result?(Y/N)" <<endl;
399     cin >> ttmp;
400     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
401     {
402         isNeg = true;
403     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
404     {
405         isNeg = false;
406     }else
407     {
408         cout << "Error input!"<<endl;
409         exit(1);
410     }
411
412     cout << "Is divisions have remainder?(Y/N)" <<endl;
413     cin >> ttmp;
414     if(ttmp == ‘y‘ || ttmp == ‘Y‘)
415     {
416         isRem = true;
417     }else if (ttmp == ‘N‘ || ttmp == ‘n‘)
418     {
419         isRem = false;
420     }else
421     {
422         cout << "Error input!"<<endl;
423         exit(1);
424     }
425
426     for(;items.size() != itemNum ;)    //根据条件生成问题
427     {
428         string num = getNum(start,end,isParentheses);
429         while (num.find(",") != string::npos)
430         {
431             addFlag = true;
432             if( num[num.find(",") + 2] == ‘(‘)     //运算符后紧跟括号,运算符选取只和isMulandDiv有关
433             {
434                 char op = getOperator("1",isMulandDiv);
435                 stringstream ss;
436                 ss << op;
437                 num = num.replace(num.find(","),1,ss.str());
438             }else                             //运算符后是数字,运算符选取和num2和isMulandDiv有关,此时是不带括号或最右边的算式
439             {
440                 string num2 = num.substr(num.find_last_of(",") + 2, num.find_first_of(")") - num.find_last_of(",") - 3);   //error at num.find(")",num.find(",") + 2) - 1
441                 char op = getOperator(num2,isMulandDiv);
442                 stringstream ss;
443                 ss << op;
444                 num = num.replace(num.find(","),1,ss.str());
445                 int begin = 0;    //找到形如 a op b 的式子
446                 if(num.find("(") != string::npos)   //如果式子里有()的话
447                     begin = num.find_last_of("(") + 2;
448                 string num1 = num.substr(begin,num.find(ss.str()) - 1);
449                 //num2 = num.substr(num.find_last_of(ss.str()) + 2,num.find_first_of(")") - 1);
450                 if(op == ‘-‘ || op == ‘+‘)
451                 {
452
453                     if(!isNeg && isNegative(num1,num2,op))
454                     {
455                         addFlag = false;
456                         break;
457                     }
458
459                 }else if(op == ‘/‘)
460                 {
461                     if(!isRem && isRemainder(num1,num2))
462                     {
463                         addFlag = false;
464                         break;
465                     }
466                 }
467             }
468
469         }
470         if(!addFlag)    //满足要求,可以添加
471         {
472             continue;
473         }
474
475         if(!isDup(items,num))    //判断是否重复,不重复则添加
476         {
477             items.push_back(num);
478         }
479     }
480     printAndCheck(items,isCmd);
481
482     return 0;
483 }由于之前是自主研究 现在变为结对开发所以我们对一份代码进行了认真的修改,以实现更多的功能 ,生成的数字和运算符之间都由空格分隔,以便于计算结果。主要添加的是bool checkResult(string exp,string result) 函数,改函数的核心就是数据结构课本上栈的应用---表达式计算。所以我们进行了,对以前栈的知识的重新学习,便于使用
运算符的优先级关系表如下:
  + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < =  
) > > > >   > >
# < < < < <   =
checkResult(string exp,string result) 中表达式是以string传入通过一个扫描标识位flag记录游标移动到的位置,
  1. 建立并初始化符号栈ops和数值栈nums,将表达式起始符 # 压入符号栈ops。
  2. 由扫描标识位flag扫描获取表达式中的数值或运算符,循环执行3~5直至求出整个表达式的值。
  3. 取出ops的栈顶元素,当ops的栈顶元素和当前扫描到的符号均为 # 时,整个表达式求值完成,这时nums的栈顶元素为表达式的值。
  4. 若取出的字符串不是运算符,则压入nums,并继续扫描。
  5. 若取出的字符串是运算符,则根据ops栈顶元素和运算符优先级比较结果,做不同处理。

    ①若 <,则运算符压入ops栈,并继续扫描。

    ②若 >,则弹出ops的栈顶运算符,从nums弹出两个数(此处弹出顺序注意),进行相应计算,结果压入nums栈。

    ③若 =,则ops的站定元素是"("且运算符是")",这时弹出ops的栈顶元素"(",相当于去掉括号,然后继续扫描。

结果的判断是用两个double类型变量进行比较。如果两者的差的绝对值小于10-4 ,则认为两数相等。

以下是运行截图:

时间: 2024-08-14 03:23:20

四则运算03 结对开发的相关文章

第三次程序-四则运算(结对开发)

接着第二周的程序,这次程序要求结对开发,并要求在第二次的基础上添加用户输入结果判断对错的功能. 结对开发伙伴: 博客名:斗破2 姓名:王文奇 博客链接:http://www.cnblogs.com/qwer111/ 功能要求: 1.乘除可控 2.随机添加括号 3.输入结果判断正误 4.统计正确数量 5.正负,余数可控 6.去除连除误区 程序思想: 1.无乘除可用0,1表示,有乘除可再加2,3,共四种选择 2.用随机函数选择左括号放在哪个操作数前面,然后再用随机函数添加右括号,在使用循环判断去除左

四则运算4 WEB(结对开发)

在第三次实验的基础上,teacher又对此提出了新的要求,实现网页版或安卓的四则运算. 结对开发的伙伴: 博客名:Mr.缪 姓名:缪金敏 链接:http://www.cnblogs.com/miaojinmin799/ 详细网页四则运算要求: 1.生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在e1-e2的子表达式,那么结果大于等于0: 2.生成的题目中如果存在形式如e1/e2的子表达式,那么其结果应该是真分数. 3.每道题目中出现的运算符个数不超过3个,括号不做详细要求. 问题分

四则运算3(结对开发)

本次试验是由上次的基础上迭代开发而来,并且用结对开发的模式进行开发. 结对开发的伙伴: 博客名:Mr.缪 姓名:缪金敏 链接:http://www.cnblogs.com/miaojinmin799/ 功能要求: 1.乘除可控 2.随机添加括号 3.输入结果判断正误 4.统计正确数量 5.正负,余数可控 6.去除连除误区 程序思想: 1.无乘除可用0,1表示,有乘除可再加2,3,共四种选择 2.用随机函数选择左括号放在哪个操作数前面,然后再用随机函数添加右括号,在使用循环判断去除左括号加在最左边

结对开发之返回一个二维整数数组中最大联通子数组的和

一.题目要求 输入一个二维整形数组,数组里有正数也有负数.二维数组首尾相接,象个一条首尾相接带子一样.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n)题目:返回一个二维整数数组中最大子数组的和 二.解题思路 先对二维数组进行了重构,形成一个环状二维数组,然后再用求二维数组子矩阵最大和的方法求得最终结果. 三.程序代码 2 #include<iostream.h> 3 int main(int argc, char* argv[]

结对开发——返回整数数组最大子数组和2

返回整数数组最大子数组和2 为了实现“敏捷开发”的目的,老师让我们采取“迭代”的方法进行项目的开发,这不,对于周一的求最大子数组和又有了新的要求,如下: 1.延续上次的要求,这里不再赘余… 2.如果数组A[0]……A[j-1]首尾相连,允许A[i-1],……A[n-1],A[0]……A[j-1]之和最大: 3.同时返回最大子数组的位置: 4.要求程序必须能处理1000 个元素,且每个元素是int32 类型的. 一.实验设计思路 首先实现的是数组首尾相连,先存入数组,再将原数组反向存储形成环形数组

结对开发5

题目:返回一个二维整数数组中最大子数组的和. 要求: 输入一个二维整形数组,数组里有正数也有负数. 二维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值.要求时间复杂度为O(n). 结对编程要求: 两人结对完成编程任务. 一人主要负责程序分析,代码编程. 一人负责代码复审和代码测试计划. 发表一篇博客文章讲述两人合作中的过程.体会以及如何解决冲突(附结对开发的工作照). 一.设计思路 这一次,因为诸多原因,我两互

结对开发——求环形二维数组最大子矩阵和的问题

一.题目要求 输入一个二维整形数组,数组里有正数也有负数.二维数组首尾相接,象个一条首尾相接带子一样.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n)题目:返回一个二维整数数组中最大子数组的和 二.解题思路 这次就在以前的基础上进行修改,先对二维数组进行了重构,形成一个环状二维数组,然后再用求二维数组子矩阵最大和的方法求得最终结果. 三.程序代码 1 #include "stdafx.h" 2 #include<i

软件工程课堂训练——结对开发之环数组最大和

一.题目及要求: 题目:返回一个整数数组中最大子数组的和 要求(新加):①如果数组A[0]...A[j-1]首尾相邻,允许A[i-1]...A[n-1],A[0]...A[j-1]之和最大:②同时返回最大子数组的位置. 结对人员:胡亚宝  焦燕 二.设计思路: 我们要解决两个问题:求出环数组中最大的子数组:并且定位出该子数组的位置,把它们的名称输出来.要解决这两个问题,我们从以下两个方面入手: ①求出最大子数组:将数组数值按顺序排好称为“一趟”,每求出一趟的最大子数组后,将第一个数值放到最后一个

结对开发体会

一,开发题目与要求: 题目:输入一个整数组,要求输出最大字数组的和. 要求:要求输入一个整数数组,可以有正有负 任意一个多个连续的整数为一个数组,求每一个字数组的和 要求输出最大数组的和,时间复杂度为O(n) 结对编程的要求: 两个人结对共同完成编程任务 一个人主要负责驾驶,即操作键盘负责代码的输入 一个人主要负责导航,即代码复审,思路探讨,程序测试检测 发表一篇两个人合作过程中的体会及如何解决问题的思路 二,设计思路: 两人共同阅读题目了解到最大子数组的概念是数组中连续的一个或多个整数组成的一