c语言卡号自动生成会不会重复,四则运算生成器: 实现一个自动生成小学四则运算题目的命令行程序。程序一次运行生成的题目不重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如...

#一、代码说明

实现一个自动生成小学四则运算题目的命令行程序。程序一次运行生成的题目不重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

#二、解题思路

首先这个题目有分数的要求,所以在一开始就应该考虑到分数的实现,因为java不存在可以处理分数运算的类,这个应该在一开始就考虑清楚,我们的处理方式是将整数与分数作为一个对象来处理,即整数就是分母为1的分数。

计算便可以直接用分数的运算了。

因为题目要求命令行,所以我们找了脚本的方法来实现命令行操作

#三、设计实现过程

有三个包,分别为service(服务包),model(实体包),main(主程序)

service里有四个类,分别包括了计算操作,分数实体类处理操作,检查操作与生成式子操作

model里有三个类,计算等式的计算类,分数类,结果集合

main里主要是以上两个包中的方法对应整合

#四、代码说明

整个程序难点就在于分数的运算,整数,小数运算可以用自带的操作运算符,但是在java里面却没有一个基本类型去表示分数。很多人可能会考虑到把分数化成小数再运算再转为分数,其实不然,有很多情况下是无法进行转换的,因为java语言中的double类型所表示的精度也是有限的。于是结合java面向对象的思想特征,应该先定义要给分数类,并封装相关的运算方法。代码如下

分数类:

/*

* 构建一个分数类,用来表示分数,封装相关的方法

*/

public class Fraction {

private int denominator;// 分母

private int nominator;// 分子

// 构建一个分数

public Fraction(int denominator, int nominator) {

super();

this.denominator = denominator;

this.nominator = nominator;

}

public Fraction(int nominator) {

this.denominator = 1;

this.nominator = nominator;

}

public Fraction() {

super();

}

// 判断构建的是一个分数还是一个整数,不超过limit的数值

public Fraction(boolean l, int limit) {

Random r = new Random();

// 这是一个分数

if (l == true) {

int index = r.nextInt(limit);

int index2 = r.nextInt(limit);

while(index==0) {

index = r.nextInt(limit);

//System.out.println("会生成0:"+index);

}

//System.out.println("不会生成0:"+index);

this.denominator = index;

this.nominator = index2;

// 这是一个整数

} else {

int index = r.nextInt(limit);

this.denominator = 1;

this.nominator = index;

}

}

public int getDenominator() {

return denominator;

}

public void setDenominator(int denominator) {

this.denominator = denominator;

}

public int getNominator() {

return nominator;

}

public void setNominator(int nominator) {

this.nominator = nominator;

}

// 加法运算

public Fraction add(Fraction r) {

int a = r.getNominator();// 获得分子

int b = r.getDenominator();// 获得分母

int newNominator = nominator * b + denominator * a;

int newDenominator = denominator * b;

Fraction result = new Fraction(newDenominator, newNominator);

return result;

}

// 减法运算

public Fraction sub(Fraction r) {

int a = r.getNominator();// 获得分子

int b = r.getDenominator();// 获得分母

int newNominator = nominator * b - denominator * a;

int newDenominator = denominator * b;

Fraction result = new Fraction(newDenominator, newNominator);

return result;

}

// 分数的乘法运算

public Fraction muti(Fraction r) { // 乘法运算

int a = r.getNominator();// 获得分子

int b = r.getDenominator();// 获得分母

int newNominator = nominator * a;

int newDenominator = denominator * b;

Fraction result = new Fraction(newDenominator, newNominator);

return result;

}

// 分数除法运算

public Fraction div(Fraction r) {

int a = r.getNominator();// 获得分子

int b = r.getDenominator();// 获得分母

int newNominator = nominator * b;

int newDenominator = denominator * a;

Fraction result = new Fraction(newDenominator, newNominator);

return result;

}

// 用辗转相除法求最大公约数

private static long gcd(long a, long b) {

return b == 0 ? a : gcd(b, a % b);

}

// 对分数进行约分

public void Appointment() {

if (nominator == 0 || denominator == 1)

return;

// 如果分子是0或分母是1就不用约分了

long gcd = gcd(nominator, denominator);

this.nominator /= gcd;

this.denominator /= gcd;

}

public int existZero(){

if(this.nominator<0||this.denominator<0){

return 0;

}else {

return 1;

}

}

}

在这个分数类中,我们定义了分子和分母,然而整数其实一个分数,只不过这个分数的分母为1.

至于运算也只是根据运算法则对分数的分子分母进行运算,保证了

在程序中,运算符的出现数量以及类型是随机的,用数组进行存储,用一个随机数Ramdon

char[] c = { '+', '-', '*', '÷' }//显示四种基本运算符

r.nextInt(4);//随机生成四种基本运算符的一种

int s = r.nextInt(3);// 生成运算符的数量

用这种随机数的形式保证了式子的随机性。随机出现,随机生成,之后只要根据多项式的运算,对式子进行运算即可。之后将生成的式子放在一个list里面,包括运算符以及分数类

运算

四则运算具有优先级,先算乘除再算加减,如果采用if表达的形式,对优先级进行判定,那么三个运算符就有64种情况,很明显是不可采取的,容易使代码失去可读性,在这种情况下,我们采取递归来解决这种问题。

//分式的计算方法

public Fraction calculate(List l){

int muldiv = MulDivExist(l);

if(muldiv != -1){

String s = MulDiv(l,muldiv);

if(s.equals("error")){

return null;

}

}else {

String s = AddSub(l);

if(s.equals("error")){

return null;

}

}

if (l.size() == 1) {

return (Fraction) l.get(0);

}

return calculate(l);

}

/*

* 判断分式里面是否有乘除

* 有乘除返回乘除的位置,没乘除返回-1

*/

public int MulDivExist(List list){

for (int i = 0; i < list.size(); i++) {

if (list.get(i).equals("*") || list.get(i).equals("/")) {

return i;

}

}

return -1;

}

//计算分式的乘除,计算结果往前放

public String MulDiv(List l,int muldiv){

String fuhao = (String) l.remove(muldiv);

Fraction first = (Fraction) l.get(muldiv-1);

Fraction last = (Fraction) l.get(muldiv);

l.remove(muldiv);

if (fuhao.equals("*")) {

Fraction result = first.muti(last);

l.set(muldiv - 1,result);

if(result.existZero()==0){

return "error";

}

}

if (fuhao.equals("/")) {

Fraction result = first.div(last);

l.set(muldiv - 1,result);

if(result.existZero()==0){

return "error";

}

}

return "right";

}

//计算分式的加减,计算结果往前放

public String AddSub(List list){

for (int i = 0; i < list.size(); i++) {

if (list.get(i).equals("+")) {

Fraction first = (Fraction) list.get(i-1);

list.remove(i);

Fraction last = (Fraction) list.get(i);

list.remove(i);

Fraction result = first.add(last);

list.set(i - 1, result);

i--;

if(result.existZero()==0){

return "error";

}

}

if (list.get(i).equals("-")) {

Fraction first = (Fraction) list.get(i-1);

list.remove(i);

Fraction last = (Fraction) list.get(i);

list.remove(i);

Fraction result = first.sub(last);

list.set(i - 1, result);

i--;

if(result.existZero()==0){

return "error";

}

}

}

return "right";

}

在递归计算之前,先做一个判定,对生成的式子进行判别,如果有乘除,那就优先采用乘除的递归,然后再用递归计算加减。这样就保证了运算的优先级问题。

去重

式子需要去重,保证每次生成的都是不一样的式子。去重采用了一种字符串比较的方法,在此之前,重写了分数类的toString方法,只要两个字符串组成字符完全相同即:组成两个式子的字符完全一样就可以说明这两个式子是重复的。

重写的toString方法

@Override

public String toString() {

Appointment();

if(this.denominator == 0){

System.out.println(this.nominator + "|" + this.denominator);

System.out.println("分母为0");

}

if (this.denominator == 1 || this.nominator == 0) {

return "" + this.nominator;

}else if (this.nominator > this.denominator) {

if(nominator % denominator==0){

return "" + nominator / denominator;

}

return "" + nominator / denominator + "," + nominator % denominator + "/" + denominator;

}else{

return "" + this.nominator + "/" + this.denominator;

}

}

去重代码:

//查重,若有重复那就返回ture

public boolean isRepeat(List> list, List set) {

if (list.size() <= 0) {

return false;

}

Iterator iterator = set.iterator();

for (List l_set : list) {

if (l_set == null || l_set.size() != set.size() || l_set.size() <= 0 || set.size() <= 0) {

continue;

}

int i = 0;

while(iterator.hasNext()){

if(l_set.contains(iterator.next())){

i = i+1;

}

}

if(i == set.size()){

return true;

}

}

return false;

}

通过这段去重代码可以将重复的式子筛选出去,保证了整个文件中式子的独立性。

计算结果的校验

一个式子,等式右边的就是结果,一个式子就是一个字符串,只要用字符串处理函数将等式右边的结果截取出来,与用户的输入进行对比就能得出结果与否。

相关代码如下:

while((str1=reader1.readLine())!=null&&(str2=reader2.readLine())!=null){

if(!str1.trim().equals(str2.trim())){

String[] str = str1.split("\\.");

error = error + str[0]+ ",";

errornum ++ ;

}else {

String[] str = str1.split("\\.");

correct = correct + str[0] + ",";

correctnum ++;

}

}

if(error.equals("")){

error = "Wrong: " + errornum + "";

}else {

error = "Wrong: " + errornum + "(" + error.substring(0,error.length()-1) + ")";

}

if(correct.equals("")){

correct = "Correct: " + correctnum + "";

}else {

correct = "Correct: " + correctnum + "("+correct.substring(0, correct.length()-1)+")";

}

m.put("wrong", error);

m.put("correct", correct);

return m;

}

将结果放在一个map中,便于读取,得出结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值