设计思路:
程序包含两部分,一部分是算式的生成,一部分是栈的使用用来判断和计算结果;
算式生成,用的是调用子函数,因为每一个年级的出题要求不同所以对出题的范围加了条件限制;程序的结构框架大致为:
程序开始将字符串数组宏定义,出题的数量和选择打印的方式都进行宏定义;
For( )
{
For( )
{
a> 产生左括号;(用switch…..case语句来判断;)
b> 产生数字:(其中,可以有分数小数和整数的产生)
其中不同年级选择的范围不同;
c>产生右括号;(右括号的产生是用左括号的数量来限制的)
d>产生运算符;运算符在输出最后一位数字之后就不会执行运算符产生的程序;)
}
}
栈程序中:
将算式生成的string类型的数组,转化为char类型的,读入到栈中,然后利用字符串优先级的判断,计算函数,我们的程序中不能出现负数所以在输出结果时加了结果判断;
//组成员:禹慧慧 吕兰兰
//四则运算,在前面的基础上实现判断正误 2016.3.19
//我们的结果是如果选择dos界面,可以在界面上实现输入结果、判断正误与给出答案;如果选择txt,则打印出一份题目和一份答案
//没有控制余数,都算成了小数
#include<iostream>
#include<ctime>
#include<cmath>
#include<sstream>
#include<string>
#include<fstream>
#define MAX 1000
using namespace std;
int N;
int way;
string str[1000];
ofstream outfile("questions.txt");
ofstream outfile_1("answers.txt");
class Input
{
public:
Input()
{
for( int i = 0;i < MAX;i++ )
Str_input[i] = '\0';
}
char Str_input[MAX];
void inStr(string str11)
{
strcpy(Str_input,str11.c_str());
}
};
/*输出模块*/
class Output
{
public:
Output()
{
result = 0;
}
void getRes( double res )
{
result = res;
}
void printRes(double &num_an)
{
num_an=result;
}
private:
double result;
};
/*计算用的存储结构*/
template <class Type>
class STACK{
private:
Type base[MAX];
int Size;
public:
STACK()
{
Size=0;
};
void push(Type a)
{
base[Size]=a;
Size++;
}
Type pop()
{
return base[--Size];
}
int size()
{return Size;}
};
/*计算的模块*/
class jisuan
{
public:
bool shuhanshu(char);
bool fuhanshu(char);
int jckh(char);
bool jcxsd(char *);
int pdyxj(char);
double ToData(char*);
double Call(double,double,char);
int ppkh(char* buffer,int pos);
void Opr( STACK<char>&, STACK<double>&, int& );
double Calculate(char*, double& );
};
bool jisuan::shuhanshu(char ch)
{
return ((ch>='0'&&ch<='9')||ch=='.')?true:false;
}
bool jisuan::fuhanshu(char ch)
{
return (ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='#')?true:false;
}
int jisuan::jckh(char ch)
{
if(ch=='(')
return 1;
if(ch==')')
return -1;
return 0;
}
bool jisuan::jcxsd(char *ch)
{
int a=0;
for(int i=0;i<strlen(ch);i++)
if(ch[i]=='.')
a++;
if(a>1)
return false;
return true;
}
int jisuan::pdyxj(char ch) //符号的优先极别
{
switch(ch)
{
case '+':
return 0;
case '-':
return 0;
case '*':
return 1;
case '/':
return 1;
case '#':
return 0;
default:
return -1;
}
}
double jisuan::ToData(char* ch) //将数字转化为数值
{
int i,j,sumn=0;
double sum=0.0;
if(!jcxsd(ch)) return 0.0;
for(i=0;i<strlen(ch);i++)
{
if(ch[i]!='.')
sumn=sumn*10+(ch[i]-'0');
else break;
}
if(i<strlen(ch))
for(j=i+1;j<strlen(ch);j++)
sum=sum*10+(ch[j]-'0');
sum /= pow(10.0,(double)(strlen(ch)-1-i));
return (sum+sumn);
}
double jisuan::Call(double sum,double data,char ch)
{
double ans=0.0;
switch(ch)
{
case '+':
ans=sum+data;
break;
case '-':
ans=sum-data;
break;
case '*':
ans=sum*data;
break;
case '/':
if( data != 0.0 )
ans=sum/data;
else
{
cout<<"程序出现除0错误,终止!\n";
system("pause");
exit(1);
}
break;
case '#':
return 0;
default:ans=0.0;
break;
}
return ans;
}
int jisuan::ppkh(char* buffer,int pos) //利用栈找到匹配的括号
{
STACK<char> Temp;
int i;
for(i=pos;i<strlen(buffer);i++)
{
if(jckh(buffer[i])==1)
Temp.push('0');
if(jckh(buffer[i])==-1)
{
Temp.pop();
if(Temp.size()==0) return i;
}
}
return -1;
}
void jisuan::Opr(STACK<char>& symbol,STACK<double>& data,int& mark)
{
double sum;
while(symbol.size()!=0)
{
char tem=symbol.pop();
int temp=pdyxj(tem);
symbol.push(tem);
if(temp<mark)
break;
else{
sum=Call(data.pop(),data.pop(),symbol.pop());
data.push(sum);
}
}
}
double jisuan::Calculate(char* buffer,double& sum) //字符串读入和各个函数调配
{
STACK<double> data;
STACK<char> symbol;
double ans;
char temp[MAX];
int ct=0,mark=0,tp=0;
data.push(sum);
while(ct<=strlen(buffer))
{
if(shuhanshu(buffer[ct])) //如果是数字或小数点
{
while( ct < strlen(buffer) && shuhanshu(buffer[ct]) )
temp[tp++]=buffer[ct++];
temp[tp]='\0';
tp=0; //读到非数字也非小数为止
ans=ToData(temp); //把读到的字符串转化为数
data.push(ans);
if(ct==strlen(buffer)) //已经独到字符串末尾
{
mark=0;
Opr(symbol,data,mark);
sum=data.pop();
return sum;
}
else{
int mark=pdyxj(buffer[ct]);
Opr(symbol,data,mark); //计算
}
}
else if(fuhanshu(buffer[ct])) //如果是运算符
symbol.push(buffer[ct++]); //运算符入symbol栈
else
{
char BF[100];int k=0; //如果都不是,则只能是括号
while( jckh( buffer[ct] ) != 1 && ct <= strlen(buffer) )
BF[k++] = buffer[ct++];
BF[k]='\0';
if(jckh(buffer[ct])==1) //一旦读到左括号,寻找它匹配的右括号
{
int i,j;
char Temp[100];
for(i=ct+1,j=0;i<ppkh(buffer,ct);i++,j++)
Temp[j]=buffer[i]; //把这对括号中的字符串存入Temp
Temp[j]='\0';
data.push(Calculate(Temp,sum));
ct+=(strlen(Temp)+1);
if(ct+1==strlen(buffer))
{
mark=0;
Opr(symbol,data,mark);
sum=data.pop();
return sum;
}
else
{
mark=pdyxj(buffer[ct+1]); //不是的话继续计算
Opr(symbol,data,mark);
}
ct++; //读入下一个字符
}
}
}
return 0.;
}
int Expression(int grade,int N)
{
Input in;
jisuan cl;
Output out;
double sum=0.0;
double result;
double answer;
cout.precision(5);
int random_a,random_b,random_c,random_e,random_f,random_g;
int max,min;//整数
int random_d;
double random_h;
//根据年级的不同选择每道题目的数的数量
if(grade==2)
{
random_a=rand()%2+2;
max=100;
min=1;
}
if(grade==3)
{
random_a=rand()%3+2;
max=500;
min=1;
}
if(grade==4)
{
random_a=rand()%3+2;
max=1000;
min=1;
}
if(grade==5)
{
random_a=rand()%3+2;
max=10000;
min=1;
}
if(grade==6)
{
random_a=rand()%3+2;
max=10000;
min=1;
}
for(int j=0;j<N;j++)
{
int flag=0;
int count_p=0,count_q=0;//计算括号的数量
for(int i=0;i<random_a;i++)
{
if(grade==2||grade==3||grade==4)
{
random_b=1;//只有整数计算
}
if(grade==5||grade==6)
{
random_b=rand()%3+0;
}
char str1[100];
//左括号的产生
if(random_a>2&&i<(random_a-1))
{
random_d=rand()%4+0;
switch(random_d)//控制括号的产生
{
case 0:flag=0;break;
case 1:if(i!=(random_a-1)&&i<(random_a-2)){str[j]+='(';flag=1;count_q+=1;}break;
case 2:flag=0;break;
case 3:if(i!=(random_a-1)&&i<(random_a-2)){str[j]+='(';flag=1;count_q+=1;}break;
}
}
//random_b=rand()%3+0;//控制数字类型
//数字的产生
switch(random_b)
{
case 0:
{
random_h=(rand()%100)/100.0;//小数
random_e=rand()%10+0;
random_h+=random_e;
stringstream ss;
ss<<random_h;
str[j]+=ss.str();
}
break;
case 1:
{
random_c=rand()%(max-min+1)+min;//整数
itoa(random_c,str1,10);
str[j]+=str1;
} break;
case 2:
{//分数
do{
random_f=rand()%20+1;
random_g=rand()%10+1;
}while(random_g==random_f);
int number=1;
int m;
if(random_g>random_f)
{
m=random_f;
}
else
{ m=random_g;}
for(int k=2;k<m+1;k++)
{
if((random_g%k==0)&&(random_f%k==0))
{
number=k;
}
}
random_f=random_f/number;
random_g=random_g/number;
str[j]+='(';
if(random_g==1)
{
int n=0;
n=random_g;
random_g=random_f;
random_f=n;
}
itoa(random_f,str1,10);
str[j]+=str1;
str[j]+='/';
itoa(random_g,str1,10);
str[j]+=str1;
str[j]+=')';
}break;
}
//右括号的产生
if((flag!=1)&&(count_p!=count_q))
{
str[j]+=')';
count_p+=1;
}
if(i==(random_a-1))
{
if(count_p<count_q)
{
for(int k=0;k<(count_q-count_p);k++)
str[j]+=')';
}
}
if(i!=(random_a-1))
{
random_b=rand()%4+0;
switch(random_b)
{
case 0:{str[j]+='+';}break;
case 1:{str[j]+='-';}break;
case 2:{str[j]+='*';}break;
case 3:{str[j]+='/';}break;
}
}
}
in.inStr(str[j]); //输入模块
out.getRes( cl.Calculate(in.Str_input,sum) ); //计算模块
out.printRes(result);
if (result<0)
{
j--;
}
else
{
if(way==1)
{
cout<<str[j]<<"="<<endl;
cout<<"请输入答案(6位有效数字):";
cin>>answer;
if (answer==result)
{
cout<<"回答正确!"<<endl;
}
else
{
cout<<"回答错误!"<<endl;
cout<<"正确结果为:"<<result<<endl;
}
}
else
{
outfile<<str[j]<<"=";
outfile<<endl;
outfile_1<<"正确结果为:"<<result;
outfile_1<<endl;
}
}
}
return 0;
}
int main()
{
int grade;
srand(time(0));
cout<<"********************************************************************************"<<endl;
cout<<"********************************************************************************"<<endl;
cout<<"***************************欢迎使用小学四则运算出题系统*************************"<<endl;
cout<<"********************************************************************************"<<endl;
cout<<"*******作者:石家庄铁道大学 信1301-2 禹慧慧 吕兰兰 2016.3.19 *******"<<endl;
cout<<"********************************************************************************"<<endl;
cout<<"请选择打印方式:(0-TXT,1-DOS):";
cin>>way;
cout<<"********************************请选择年级**************************************"<<endl;
cout<<" 2年级 "<<endl;
cout<<" 3年级 "<<endl;
cout<<" 4年级 "<<endl;
cout<<" 5年级 "<<endl;
cout<<" 6年级 "<<endl;
cin>>grade;
cout<<"请输入题目数量:";
cin>>N;
if(grade==2)
{
Expression(grade,N);
}
if(grade==3)
{
Expression(grade,N);
}
if(grade==4)
{
Expression(grade,N);
}
if(grade==5)
{
Expression(grade,N);
}
if(grade==6)
{
Expression(grade,N);
}
outfile.close();
outfile_1.close();
}





项目计划日志(单位:h)
|
听课 |
编写程序 |
阅读相关书籍 |
网上查找资料 |
日总计 |
|
|
周一 |
2 |
0 |
1 |
0 |
3 |
|
周二 |
0 |
3 |
0.5 |
3.5 |
|
|
周三 |
0 |
3 |
1 |
0 |
4 |
|
周四 |
2 |
6 |
1 |
9 |
|
|
周五 |
0 |
4 |
0 |
2 |
6 |
|
周六 |
0 |
3 |
1 |
4 |
|
|
周日 |
|||||
|
周总计 |
4 |
19 |
2 |
4.5 |
29.5 |
时间记录日志:(单位:min):
|
日期 |
开始时间 |
结束时间 |
中断时间 |
净时间 |
活动 |
备注 |
|
星期一 |
14:00 |
15:50 |
10 |
100 |
听课 |
软件工程 |
|
20:00 |
21:00 |
0 |
60 |
看书 |
构建之法 |
|
|
星期二 |
19:00 |
19:30 |
0 |
30 |
网上查找资料 |
|
|
20:00 |
23:00 |
0 |
180 |
编程 |
结对编程 |
|
|
星期三 |
15:00 |
22:00 |
180 |
240 |
编程和上网查找资料并且调试程序 |
结对编程 |
|
星期四 |
14:00 |
15:50 |
10 |
100 |
听课 |
软件工程 |
|
16:00 |
23:00 |
60 |
360 |
编程 |
结对编程 |
|
|
星期五 |
16:00 |
21:00 |
30 |
270 |
编程上网查找资料 |
结对编程 |
|
星期六 |
19:00 |
22:00 |
0 |
180 |
编程和写博客 |
结对编程 |
缺陷记录日志:
|
日期 |
编号 |
类型 |
引入阶段 |
排除阶段 |
修复时间 |
修复缺陷 |
|
3/17 |
1 |
20 |
编码 |
调试 |
20:00 |
括号输出错误,运算不正确 |
|
3/18 |
2 |
20 |
编码 |
调试 |
19:00-21:00 |
对栈的编写和运算结果 |
|
3/19 |
3 |
20 |
编码 |
调试 |
20:00-22:00 |
括号的丢失和语法的错误。 |
组成员吕兰兰网址:http://www.cnblogs.com/lvlan/