题目要求:
1.程序可以判断用户的输入答案是否正确,如果错误,给出正确答案,如果正确,给出提示。
2.程序可以处理四种运算的混合算式。
3.要求两人合作分析,合作编程,单独撰写博客。
团队成员:张绍佳、杜文星(博客:http://www.cnblogs.com/duwenxing/p/5294508.html)
设计思路:
代码分写于不同的文件中;
① head.h:在头文件head.h中,将其他.cpp文件中所需要的头文件、全局变量的声明、函数的声明都写在此文件中。
② fraction.cpp:此文件中主要定义了一些与分数有关的函数,如分数的生成化简、加减乘除、分数的输出、分数转字符串等。
③ stack.cpp:此文件的主要功能是将所给的运算式的结果计算出来,主要思路是利用栈先将运算式转化为后缀式,然后再利用栈将后缀式的结果求出,重难点是转化后缀式时如何将真分数当做一个整体,我们的解决方法是通过识别 “(” 和 “)” 来识别;同时在计算时即使是整数我们也将其转化为分数处理,故调用了fraction中的一些方法来进行加减乘除。
④yunsuan.cpp:这个文件的主要功能是实现运算式的生成,并判断使用者输入的结果和题目的答案是否相同来判断对错,并输出正确数与错误数。
⑤main.cpp:主函数所在的头文件,主要功能是和用户进行交互。
工作照:
代码:
head.h
#pragma once
#include<iostream>
#include<ctime>
#include<strstream>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstdio>
#include<cmath>
#define random(l,h) (rand()%(h-l+1)+l)//宏定义
#define maxsize 1000
using namespace std;
extern int flag;
/*stack.cpp*/
struct Fraction
{
int up, down;
string high, low;
};
void trans(string exp, char postexp[]);
Fraction compvalue(char postexp[]);//计算后缀表达式的值
/*fraction.cpp*/
int gcd(int a, int b);//求a,b的最大公约数
int max(int a, int b);
int min(int a, int b);
Fraction fraction(int up, int down);//生成分数
Fraction fra(int d, int u);//生成真分数;
Fraction reduction(Fraction result);//分数的化简
Fraction add(Fraction f1, Fraction f2);//分数的加法
Fraction minus1(Fraction f1, Fraction f2);//分数的减法
Fraction multi(Fraction f1, Fraction f2);//分数的乘法
Fraction divide(Fraction f1, Fraction f2);//分数的除法
void ShowResult(Fraction f);//输出分数
string FraToString(Fraction f);//将分数转换为string类型
/*yunsuan.cpp*/
int suiji(int down, int up);//随机生成1至n的整数
bool is_unique(string str, vector <string> s);//判断生成的运算式是否重复
void yunsuan(int time, int low, int high, int fl1, int fl2, int fl3);
fraction.cpp
#include"head.h"
int gcd(int a, int b)//求a,b的最大公约数
{
if (b == ) return a;
else return gcd(b, a%b);
} int max(int a, int b)//返回两个整数中较大的整数
{
int h = a >= b ? a : b;
return h;
}
int min(int a, int b)//返回两个整数中较小的整数
{
int l = a <= b ? a : b;
return l;
}
Fraction fraction(int up, int down)//生成分数
{
Fraction result;
result.up = up;
result.down = down;
strstream ss, kk;
ss << result.up; ss >> result.high;
kk << result.down; kk >> result.low;
return result;
}
Fraction fra(int d,int u)//生成真分数
{
Fraction result;
int temp1 = suiji(d, u);//调用function函数随机生成两个随机整数
int temp2 = suiji(d, u);
result.up = min(temp1, temp2);
result.down = max(temp1, temp2);
strstream s1, s2;
s1 << result.up; s1 >> result.high;
s2 << result.down; s2 >> result.low;
return result;
}
Fraction reduction(Fraction result)//分数的化简
{
if (result.down < )
{
result.up = -result.up;
result.down = -result.down;
}
if (result.up == )
{
result.down = ;
}
else
{
int d = gcd(abs(result.up), abs(result.down));
result.up /= d;
result.down /= d;
}
strstream s3, s4;
s3 << result.up; s3 >> result.high;
s4 << result.down; s4 >> result.low;
return result;
}
Fraction add(Fraction f1, Fraction f2)//分数的加法
{
Fraction result;
result.up = f1.up*f2.down + f1.down * f2.up;
result.down = f1.down*f2.down;
return reduction(result);
}
Fraction minus1(Fraction f1, Fraction f2)//分数的减法
{
Fraction result;
result.up = f1.up*f2.down - f1.down*f2.up;
result.down = f1.down*f2.down;
return reduction(result);
}
Fraction multi(Fraction f1, Fraction f2)//分数的乘法
{
Fraction result;
result.up = f1.up*f2.up;
result.down = f1.down*f2.down;
return reduction(result);
}
Fraction divide(Fraction f1, Fraction f2)//分数的除法
{
Fraction result;
result.up = f1.up*f2.down;
result.down = f1.down*f2.up;
return reduction(result);
}
void ShowResult(Fraction f)//输出分数
{
f = reduction(f);
if (f.down == ) cout << f.up;
else cout << f.up << "\\" << f.down;
}
string FraToString(Fraction f)//将分数转换为string类型
{
string result;
if (f.down == ) result = f.high;
else result = f.high + "\\" + f.low;
return result;
}
stack.cpp
#include"head.h"
struct
{
char data[maxsize];//存放运算符
int top;//栈顶指针
}op;//定义运算符栈
void trans(string exp, char postexp[])//exp[]为算数表达式,postexp[]为后缀表达式
{
char ch;
int i = , j = ;//i作为exp的下标,j作为postexp的小标
op.top = -;
ch = exp[i];
i++;
while (ch != '\0')//exp表达式未扫描完时循环
{
switch (ch)
{
case'['://判定为左括号
{
op.top++;
op.data[op.top] = ch;
}break;
case']'://判定为右括号,此时将’[‘之前的运算符依次出栈并存放到postexp中
{
while (op.data[op.top] != '[')
{
postexp[j] = op.data[op.top];
j++;
op.top--;
}
op.top--;//将’[‘删除
}break;
case'+'://为’+‘或’-‘时,其优先级不大于栈顶的任何运算符,直到’]‘为止
case'-':
{
while (op.top != - && op.data[op.top] != '[')
{
postexp[j] = op.data[op.top];
j++;
op.top--;
}
op.top++;
op.data[op.top] = ch;
}break;
case'*'://为’*‘或’/’时,其优先级不大于栈顶为‘*’或‘/‘的优先级,直到’['
case'/':
{
while (op.top != - && op.data[op.top] != '[' && (op.data[op.top] == '*' || op.data[op.top] == '/'))
{
postexp[j] = op.data[op.top];
j++;
op.top--;
}
op.top++;
op.data[op.top] = ch;
}break;
case' ':break;//过滤掉空格
case'('://将分数当成一个整体放到postexp中
{
while (ch != ')')
{
postexp[j]=ch;
j++;
ch = exp[i];
i++;
}
postexp[j]=ch; j++;//将')'放到postexp中
}break;
default:
{
while (ch >= ''&&ch <= '')//判定为数字
{
postexp[j] = ch;
j++;
ch = exp[i];
i++;
}
i--;
postexp[j] = '#';//用#标示一个数值的结束
j++;
}
}
ch = exp[i];
i++;
}
while (op.top != -)//此时exp扫描完毕,栈不空时出栈并存放到postexp中
{
postexp[j] = op.data[op.top];
j++;
op.top--;
}
postexp[j] = '\0';//给postexp表达式添加结束标识
}
struct
{
Fraction data[maxsize];//存放数值
int top;//栈顶指针
}st;
Fraction compvalue(char postexp[])//计算后缀表达式的值
{
double d;
char ch;
int i = ;//postexp的下标
st.top = -;
ch = postexp[i];
i++;
while (ch != '\0')//postexp字符串未扫描完事完成循环
{
switch (ch)
{
case'+':
{
st.data[st.top - ] = add(st.data[st.top - ], st.data[st.top]);
st.top--;
}break;
case'-':
{
st.data[st.top - ] = minus1(st.data[st.top - ], st.data[st.top]);
st.top--;
}break;
case'*':
{
st.data[st.top - ] = multi(st.data[st.top - ], st.data[st.top]);
st.top--;
}break;
case'/':
{
st.data[st.top - ] = divide(st.data[st.top - ], st.data[st.top]);
st.top--;
}break;
case'(':
{
double high = , low = ;
ch = postexp[i]; i++;//删除‘(‘
while (ch != '\\')
{
high = * high + ch - '';
ch = postexp[i];
i++;
}
ch = postexp[i]; i++;//删除’\’
while (ch != ')')
{
low = * low + ch - '';
ch = postexp[i];
i++;
}
st.top++;
Fraction re = fraction(high, low);
st.data[st.top] = re;
}break;
default:
{
d = ;
while (ch >= ''&&ch <= '')//将数字字符转化为对应的数值存放到d中
{
d = * d + ch - '';
ch = postexp[i];
i++;
}
st.top++;
Fraction re = fraction(d, );
st.data[st.top] = re;
}
}
ch = postexp[i];
i++;
}
return st.data[st.top];
}
yunsuan.cpp
#include"head.h"
int flag = ;
int suiji(int down, int up)//随机生成1至n的整数
{
int low = down, high = up;
if (flag)
{
flag = ;
srand((unsigned)time(NULL));//种子
}
int result = random(down, up);
return result; }
bool is_unique(string str, vector <string> s)//判断生成的运算式是否重复
{
int count = ;
for (int i = ; i < s.size(); i++)
{
if (str!=s[i])
{
count++;
}
else break;
}
bool flag0 = count == s.size() ? true : false;
return flag0;
}
void yunsuan(int time, int low, int high, int fl1, int fl2, int fl3)//根据参数要求生成四则运算式
{
int integer1, integer2;
int ch1, ch2, ch3, ch4;//switch语句的选项
char sign;//运算符号
int times = time;//题目数
vector <string> str;//str用来保存生成的题目
int right = , wrong = ;
for (int i = ; i <= times;)
{
int flag4 = ;//flag4用来标记运算式是否是刚开始生成
string first, second, cal;//四则运算的第一个运算数和第二个运算数
int number = suiji(, );//number为参与运算的参数个数
for (int j = ; j <= number;)
{
//-------------------------------------------------------------------------------------
if (fl1 == )//允许乘除发参与运算的情况
{
ch1 = suiji(, );//随机生成运算符号
switch (ch1)
{
case :sign = '+'; break;
case :sign = '-'; break;
case :sign = '*'; break;
case :sign = '/'; break;
default:cout << "有错误!" << endl; break;
}
}
else//不允许乘除法参与运算的情况
{
ch1 = suiji(, );//随机生成运算符号
switch (ch1)
{
case :sign = '+'; break;
case :sign = '-'; break;
default:cout << "有错误!" << endl; break;
}
}
//-------------------------------------------------------------------------------------
if (fl3 == )//允许真分数参与运算
{
ch2 = suiji(, );//四则运算题目的三种情况
switch (ch2)
{
case ://整数和整数
{
strstream si, so;
integer1 = suiji(low, high);
si << integer1; si >> first;
integer2 = suiji(low, high);
so << integer2; so >> second;
}break;
case ://整数和真分数
{
strstream ss;
integer1 = suiji(low, high);
ss << integer1; ss >> first;
Fraction f = reduction(fra(low, high));
second = "(" + f.high + "\\" + f.low + ")";
}break;
case ://真分数和真分数
{
Fraction f1 = reduction(fra(low, high));
Fraction f2 = reduction(fra(low, high));
first = "(" + f1.high + "\\" + f1.low + ")";
second = "(" + f2.high + "\\" + f2.low + ")";
}break;
default:cout << "有错误!" << endl; break;
}
}
else//不允许真分数参与运算
{
strstream si, so;
integer1 = suiji(low, high);
si << integer1; si >> first;
integer2 = suiji(low, high);
so << integer2; so >> second;
}
//-------------------------------------------------------------------------------------
if (fl2 == )//允许括号(【】)参与运算
{
ch4 = suiji(, );
switch (ch4)
{
case :
{
if (flag4 == )//flag4为1表示运算式还未生成前两个运算数
{
cal = first + sign + second;
flag4 = ;
}
else
{
cal = cal + sign + first;//将以生成的运算式个新生成的运算数连接起来
}
}break;
case :
{
if (flag4 == )
{
cal = second + sign + first;
flag4 = ;
}
else
{
cal = second + sign + cal;
}
}break;
case :
{
if (flag4 == )
{
cal = "[" + first + sign + second + "]";//添加括号【】的情况
flag4 = ;
}
else
{
cal = "[" + cal + sign + first + "]";
}
}break;
case :
{
if (flag4 == )
{
cal = "[" + second + sign + first + "]";
flag4 = ;
}
else
{
cal = "[" + second + sign + cal + "]";
}
}break;
default:cout << "有错误!" << endl; break;
}
}
else//不允许括号(【】)参与运算
{
ch4 = suiji(, );//输出的两种情况
switch (ch4)
{
case :
{
if (flag4 == )
{
cal = first + sign + second;
flag4 = ;
}
else
{
cal = cal + sign + first;
}
}break;
case :
{
if (flag4 == )
{
cal = second + sign + first;
flag4 = ;
}
else
{
cal = second + sign + cal;
}
}break;
default:cout << "有错误!" << endl; break;
}
}
j++;
}
//------------------------------------------------------------------------------
if (str.empty())//若sr为空,则将第一个生成的运算式添加到vector中
{
str.push_back(cal);
cout << "(" << i << ")." << cal << "="; string answer;
cin >> answer;
char postexp[maxsize];
trans(cal, postexp);
Fraction re = compvalue(postexp);
string result = FraToString(re);
if (answer == result)
{
cout << "正确!" << endl;
right++;
}
else
{
cout << "错误!,正确答案为:" << result << endl;
wrong++;
}
i++;
}
if (is_unique(cal, str))//判断生成的运算式和之前已经生成的运算式是否重复
{
str.push_back(cal);//将生成的运算式添加到str中
cout << "(" << i << ")." << cal << "=";
string answer;
cin >> answer;
char postexp[maxsize];
trans(cal, postexp);
Fraction re = compvalue(postexp);
string result = FraToString(re);
if (answer == result)
{
cout << "正确!" << endl;
right++; }
else
{
cout << "错误!,正确答案为:" << result << endl;
wrong++;
}
i++;
}
else {}
}
cout << "**********************************************************************************" << endl;
cout << "你做对了" << right << "道题,做错了" << wrong << "道题" << endl;
}
main.cpp
#include"head.h"
int main()
{
cout << "请输入题目数(1~100):";
int times, down, up, flag1, flag2, flag3, flag4;
cin >> times;//times至题目数
cout << "请输入数值绝对值范围:";
cin >> down >> up;//[down,up]为运算数范围
cout << "是否允许乘除发参与运算(y/n):";
char yn1;
cin >> yn1;
yn1 == 'y' || yn1 == 'Y' ? flag1 = : flag1 = ;
cout << "是否允许括号([])参与运算(y/n):";
char yn2;
cin >> yn2;
yn2 == 'y' || yn2 == 'Y' ? flag2 = : flag2 = ;//flag2判断是否允许括号参与运算
cout << "是否允许真分数参与运算(y/n):";
char yn3;
cin >> yn3;
yn3 == 'y' || yn3 == 'Y' ? flag3 = : flag3 = ;//flag3判断是否允许真分数参与运算
cout << "**********************************************************************************" << endl;
yunsuan(times, down, up, flag1, flag2, flag3);
system("pause");
return ;
}
截图:
项目计划总结:
日期\任务 | 听课/时 | 编写程序/时 | 查阅资料/时 | 日总计/时 |
星期一 | 2 | 2 | 4 | |
星期二 | 2 | 2 | ||
星期三 | 3 | 1 | 4 | |
星期四 | 2 | 3 | 5 | |
星期五 | 4 | 4 | ||
星期六 | 5 | 2 | 7 | |
星期日 | ||||
周总计 | 4 | 19 | 3 |
26 |
时间记录日志:
日期 | 开始时间 | 结束时间 | 中断时间 | 净时间/分 | 活动 | 备注 |
3/14 | 14:00 | 15:50 | 10 | 100 | 听课 | 软件工程上课 |
19:00 | 21:00 | 60 | 编写程序 | 作业 | ||
21:00 | 21:30 | 30 | 阅读书籍 | 《构建之法》 | ||
3/15 | 19:00 | 21:00 | 20 | 90 | 查资料,编写程序 | 作业 |
3/16 | 15:00 | 16:30 | 15 | 90 | 编写程序 | 作业 |
17:00 | 18:00 | 60 | 查阅资料和阅读构建之法 | |||
21:00 | 22::00 | 60 | 编写程序 | 作业 | ||
3/17 | 14:00 | 15:50 | 10 | 100 | 听课 | 软件工程上课 |
18:30 | 22:10 | 50 | 查资料,编写程序 | 作业 | ||
3/18 | 16:20 | 18:30 | 10 | 120 | 编程 | |
19:10 | 21:45 | 145 | 查阅资料+编程 | |||
3/19 | 9:00 | 11:40 | 160 | 编程 | 作业 | |
12:20 | 15:00 | 160 | 调试程序 | |||
15:00 | 写博客 |
缺陷日志:
日期 | 编号 | 缺陷内容 | 引入阶段 | 排除阶段 | 修复时间 | 修复缺陷 |
3月14日 | 1 |
如何计算运算 式 |
编写代码 | 思考、查资料 | 80+ | 利用栈来实现 |
3月18日 | 2 |
如何识别真分 数 |
编写代码 | 思考、查资料 | 120+ | 利用“(” 和 “)”来识别 |