结对项目:四则运算题目生成--第一阶段
1、第一阶段要求
写一个能自动生成小学四则运算的命令行“软件”,分别满足下面的各种需求。
下面这些需求都可以用命令行参数的形式来指定:
a)一次可以出一千道题目,并且没有重复的,把题目写入一个文件中。
b)逐步扩展功能和可以支持的表达式类型,最后可以支持最多10个运算符,括号数量不限制的表达式。
c)出了整数以外,还要支持真分数的四则运算。(例如:1/6+1/8=7/24)
d)让程序能接受用户输入答案,并判定对错,最后给出总共 对/错 的数量。
2、解题思路
题目要求一次可以出一千道题目,所以考虑运用随机数生成操作数和操作码,然后以文件流的形式输出写入文件,允许输入小于1000的数值来控制输出题数;在进行真分数的四则运算时,先转换为浮点数的运算,然后再将结果转换为分数:当用户通过运算输入答案后,程序判断对错,此时需要对四则运算表达式进行求值,可利用以前学过的栈的相关知识;因为程序要实现多个功能,所以用输入不同的不同的数字来控制执行不同功能。
3、程序设计实现过程
(1)、 生成题目时,通过输入num的值来控制执行生成函数的次数,生成对应数目的题目,生成函数中用随机数rand()生成表达式长度和操作数以及操作符,然后将生成的题目保存到question.txt文件中;
(2)、运用栈来进行表达式求值:
以表达式“7+(5-1)*3+9/2”为例,首先将中缀表达式转化为后缀表达式,转化规则为:从左到右遍历中缀表达式的每一数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈 顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
示例步骤:
a.初始化一空栈,用来对符号进出栈使用。
b.第一个字符是数字7,输出7,后面是符号“+”,进栈。
c.第三个字符是“(”,依然是符号,因其只是左括号,还没有配对,故进栈。
d.第四个字符是数字5,输出,总表达式为7 5,接着是“-”,进栈。
e.接下来是数字1,输出,总表达式为7 5 1,后面是符号“)”,此时,我们需要去匹配此前的“(”,所以栈顶依次出栈,并输出,直到“(”出栈为止。此时左括号上方只有“-”,因此输出“-”。总的表达式为7 5 1 -。
f.接着是数字3,输出,总的表达式为7 5 1 - 3.紧接着是符号“*”,因为此时的栈顶符号为“+”号,优先级低于“*”,因此不输出,“*”进栈。
g.之后是符号“+”,此时当前栈顶元素“*”比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”更低的优先级,所以全部出栈),总输出表达式为7 5 1 - 3 * +。然后将当前这个符号“+”进栈。
h.紧接着数字9,输出,总表达式为7 5 1 - 3 * + 9。后是符号“/”,所以“/”进栈。
i.最后一个数字2,输出,总的表达式为7 5 1 - 3 * + 9 2。
j.因已经到最后,所以将栈中符号全部出栈并输出。
所以最终后缀表达式结果为:7 5 1 - 3 * + 9 2 / +
(3)、真分数计算:先将真分数转化为浮点数,进行浮点数的四则运算,再通过转化函数将结果的浮点数转化为分数。
(4)、功能选择:给予用户相关指引输入数字进行功能选择
4、代码说明
(1)、题目生成函数
void create() //生成
{
int x; //被操作数
int y; //操作数
int z; //运算符 + - * / ^
int w; //运算符+ -
int bracket; //括号
int b_flag=1;
int len; //表达式长度
int temp;
len=rand()%1+2;
……
}
(2)、表达式求值
操作符优先级比较
int mycmp(char a, char b) {
if(b == '(')
return 1;//左括号直接入栈
else if((b == '^') &&(a == '+' || a == '-' || a == '*' || a == '/' || a == '('))
return 1;//^优先级高于+、-、*、/、(,入栈
else if((b == '*' || b == '/') &&(a == '+' || a == '-' || a == '('))
return 1;//*、/优先级高于+、-、(,入栈
else if((b == '+' || b == '-') && (a == '('))
return 1;//+、-优先级高于(,入栈
else
return 0;
}
中缀表达式转后缀表达式
/*中缀表达式转后缀表达式
中缀表达式之间无分割
后缀表达式操作数、操作符之间用空格分割,便于区分不同操作数*/
void infix_to_suffix(char* infix, char* suffix) {
int i, k, j=0, top=0;
char stack[1000];//存储运算符的栈
for(i=0; infix[i]!='\0'; i++) {
if(infix[i] >= '0' && infix[i] <= '9') {
suffix[j++] = infix[i];//操作数则直接输出
} else {
if(i != 0 && infix[i-1] >= '0' && infix[i-1] <= '9') {
suffix[j++] = ' ';//操作数后补充空格分割
}
if(infix[i] == ')') {
//遇到右括号则一直弹出直到左括号,但左括号不输出
while(stack[top-1] != '(') {
suffix[j++] = stack[--top];
suffix[j++] = ' ';
}
top--;
} else if(top == 0 || mycmp(stack[top-1], infix[i])) {
//栈为空或当前操作符的优先级高于栈顶操作符,当前操作符入栈
stack[top++] = infix[i];
} else {
//当前操作符优先级等于或低于栈顶操作符则弹出栈顶
while(!mycmp(stack[top-1], infix[i])) {
suffix[j++] = stack[--top];
suffix[j++] = ' ';
if(top == 0)
break;
}
stack[top++] = infix[i];//当前操作符入栈
}
}
}
//补充空格分割
if(suffix[j-1] != ' ') {
suffix[j++] = ' ';
}
//如果操作符栈不为空,弹出所有操作符
while(top != 0) {
suffix[j++] = stack[--top];
suffix[j++] = ' ';
}
suffix[j] = '\0';
}
后缀表达式求值
double suffix_value(char* suffix) {
int i, j;
char op;
double stack[1000];
int top = 0;
double value = 0;
……
}
(3)、求最大公因数函数,辅助真分数计算
int gcd(long int m,long int n)
{
while(m%n!=0){
int t=m%n;
m=n;
n=t;
}
return n;
}
(4)、功能选择
printf("输入0表示生成题目,输入1表示答题,输入2表示求值\n");
(scanf("%d",&lab))
printf("输入生成的题目数量,题目数量小于1000:\n");
scanf("%d",&num);
printf("输入答案(答案可以用分数或者小数表示):\n");
scanf("%s",ans); //输入答案,可能为带/号的表达式
(5)、接受用户答案,统计对错题数
my_answer=atof(ans);
if( fabs(my_answer-right_answer )<inf){
printf("right!\n");
score++;
}
else{
printf("wrong!\n");
printf("my answer is %s\n",ans);
float_to_fraction(right_answer);
}
printf("得分:%d / %d",score,num);
浙公网安备 33010602011771号