题目要求:
老师提出了新的要求:
定义:
自然数:0, 1, 2, …。
真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
运算符:+, −, ×, ÷。
括号:(, )。
等号:=。
分隔符:空格(用于四则运算符和等号前后)。
算术表达式:
e := n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),
其中e, e1和e2为表达式,n为自然数或真分数。
四则运算题目:e = ,其中e为算术表达式。
1、定义参数控制生成题目的个数。
例如,参数n=10;则将生成10个题目。
2、定义参数控制题目中数值(自然数、真分数和真分数分母)的范围。
例如参数r= 10,将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。
该参数必须给定,否则程序报错并给出帮助信息。
3、生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。
4、生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
5. 每道题目中出现的运算符个数不超过3个。
6.程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目
例如,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,它们之间不能通过有限次交换变成同一个题目
7.生成的题目存储到数据库中,
格式如下:
1. 四则运算题目1
2. 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
8. 在生成题目的同时,计算出所有题目的答案,并存入数据库文件。
格式如下:
1. 答案1
2. 答案2
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
9. 程序应能支持一万道题目的生成。
10. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,
统计结果输出到数据表文件Grade,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。
-----------------------------------------------------------------------------------------
一、程序的设计思想
构造如下几个类:
试题类(class ShiTi):
属性:运算式、运算式结果、运算式逻辑运算顺序和运算数个数
公共方法:各个属性的set/get方法,
setTiMu方法中在设置了题目属性后立即设置运算数的个数并执行计算运算式结果的函数
在计算运算式结果的函数中,利用堆栈将运算式转换为后缀表达式进行计算,
每计算一个子表达式就将该表达式的运算数和运算符用逗号分隔添加到运算顺序字符串变量后
试题操作类(class ShiTiOperator):
公共方法:随机生成一个试题、判断两个试题是否逻辑相同
判断两个试题是否相同设计思想:
先比较两个运算式的运算数的个数,如果运算数个数不相同则运算式肯定不同,否则继续判断
比较两个运算式的答案是否相同,不同则返回FALSE,否则继续比较
获取两个试题的逻辑运算顺序字符串,并用‘,’对该字符串分割为一个字符串数组a
获取每一个子表达式,字符串数组a中没3个元素为一组子表达式,判断两运算式的该子表达式是否相同,
如果子表达式的运算符是加或乘则运算数可以翻转进行判断
分数类(class FenShu):
属性:分子、分母、该分数是否成立(如果分母是0就不成立)
公共方法:参数为分子分母的构造函数,参数为字符串的构造函数,分数乘除加减的函数
数据库单元类(class DBUtil):
公共方法:获取数据库的连接、释放资源
获取数据库连接的方法是将注册数据库驱动,获得一个数据库的连接进行封装,返回一个数据库连接对象
释放资源的方法是将释放查询数据库结果集对象、数据库操作对象和数据库连接对象进行封装
试题数据库操作类(ShiTiDAO):
公共方法:将一个试题对象集合插入到数据库
将一个试题对象集合插入到数据库的详细过程为:调用数据库单元类的获取数据库连接方法获取一个数据库连接对象,
构建一个sql语句为插入的数据库操作对象,
循环执行----(从试题对象中获取题目和答案等信息对参数进行设置,数据库操作对象执行)即可将多条试题信息插入到数据库
调用数据库单元类的释放资源方法释放资源
自定义异常类(class MyException):
用于对函数参数检测抛出异常,给出错误信息。
四则运算主类(class SiZe3):
公共方法:菜单、生成试题、验证统计文件中的试题
菜单方法:提供两种选项可以生成试题,可以对验证统计文件中的试题的正确性
生成试题方法:
调用试题操作类的生成试题的方法生成一个试题,并调用试题类的验证试题是否重复的方法进行重复校验,不重复则将该题目对象添加到题目list中
调用试题数据库操作类的插入数据的方法将生成的试题插入到数据库
验证统计文件中的试题方法:
从试题文件中读取试题题目,构建成试题对象,从试题对象中获取正确答案与答案文件中读取的答案进行比较,如果相同则该题目答案正确,将题号记录到一个整型的list中,否则该题目答案错误,将答案记录到另一个整型的list中。
最后将两个记录正确题号和记录错误题号的list信息写入到grade.txt文件中
二、源程序代码
package siZe3; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; //连接数据库封装类, /* * 静态方法有获得数据库的连接、关闭数据库 */ public class DBUtil { private static final String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";// 连接MySQL数据库的驱动信息 private static final String url = "jdbc:sqlserver://localhost:1433;DatabaseName=shiTiKu01";// 连接SQL Server数据库的用户名 private static final String userName = "sa";// 连接SQL Server数据库的用户名 private static final String userPwd = "218028";// 连接数据库的用户名的密码 // private static final String dbName = "shiTiKu";// 数据库名 private static Connection conn=null; private static PreparedStatement pstmt=null; private static ResultSet rs=null; public static void main(String[] args) { conn = getDBConnection(); // PreparedStatement pstmt = null; // ResultSet rs = null; closeRS(conn, pstmt, rs); } public static Connection getDBConnection() { // 定义连接URL // String url1 = "jdbc:jtds:sqlserver://localhost:1433/" + dbName; //String url2 = "?user=" + userName + "&password=" + userPwd; //String url3 = "&useUnicode=true&characterEncoding=UTF-8"; //String url = url1 + url2 + url3; //Connection conn = null; try { Class.forName(driverName);// 注册驱动 conn = DriverManager.getConnection(url,userName,userPwd);// 获得连接 } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; } // 释放资源 public static void closeRS(Connection conn, PreparedStatement pstmt, ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { if (pstmt != null) { pstmt.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { if (conn != null) { conn.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
package siZe3; public class FenShu { private int denominator, numerator; private boolean chengLi; public int getDenominator() { return denominator; } public void setDenominator(int denominator) { this.denominator = denominator; } public int getNumerator() { return numerator; } public void setNumerator(int numerator) { this.numerator = numerator; } public boolean isChengLi() { return chengLi; } public void setChengLi(boolean chengLi) { this.chengLi = chengLi; } public FenShu(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; if (denominator == 0) { this.chengLi = false; } else { this.chengLi = true; yueJian(); } } // 根据字符串构造分数 public FenShu(String str) { if(str == null) { this.chengLi = false; } int index = str.indexOf("/"); if (index == -1) { this.numerator = Integer.parseInt(str); this.denominator = 1; this.chengLi = true; } else { this.denominator = Integer.parseInt(str.substring(index + 1)); if (this.denominator == 0) { chengLi = false; } else { chengLi = true; int zhengShu = str.indexOf("'"); if (zhengShu == -1) { // 没有整数部分 this.numerator = Integer.parseInt(str.substring(0, index)); } else { // 有整数部分 this.numerator = Integer.parseInt(str.substring(0, zhengShu)) * this.denominator + Integer.parseInt(str.substring(zhengShu + 1, index)); } yueJian(); } } } public FenShu() { } // 约简 private void yueJian() { int y = 1; for (int i = numerator; i > 1; i--) { if (numerator % i == 0 && denominator % i == 0) { y = i; break; } } // int nc = numerator,dc = denominator; // if(nc != 0){ // while(nc != dc - nc){ // y = dc - nc; // if(nc > y){ // dc = nc; // nc = y; // }else{ // dc = y; // } // } // y = nc; // numerator /= y; denominator /= y; } // 加 public FenShu add(FenShu b) { FenShu c = null; if (this.chengLi && b.isChengLi()) { int nNumerator = this.numerator * b.getDenominator() + this.denominator * b.getNumerator(); int nDenominator = this.denominator * b.getDenominator(); c = new FenShu(nNumerator, nDenominator); } else { c = new FenShu(); c.setChengLi(false); } return c; } // 减 public FenShu subtract(FenShu b) { FenShu c = null; if (this.chengLi && b.isChengLi()) { int nNumerator = this.numerator * b.getDenominator() - this.denominator * b.getNumerator(); int nDenominator = this.denominator * b.getDenominator(); c = new FenShu(nNumerator, nDenominator); } else { c = new FenShu(); c.setChengLi(false); } return c; } // 乘 public FenShu multiply(FenShu b) { FenShu c = null; if (this.chengLi && b.isChengLi()) { int nNumerator = this.numerator * b.getNumerator(); int nDenominator = this.denominator * b.getDenominator(); c = new FenShu(nNumerator, nDenominator); } else { c = new FenShu(); c.setChengLi(false); } return c; } // 除 public FenShu divide(FenShu b) { FenShu c = null; if (this.chengLi && b.isChengLi() && (b.getNumerator() != 0)) { int nNumerator = this.numerator * b.getDenominator(); int nDenominator = this.denominator * b.getNumerator(); c = new FenShu(nNumerator, nDenominator); } else { c = new FenShu(); c.setChengLi(false); } return c; } // 输出分数形式 public String toString() { if (this.chengLi) { if (numerator != 0) { if (numerator % denominator == 0) return "" + numerator / denominator; else if (numerator > denominator) { return (numerator / denominator) + "'" + (numerator % denominator) + "/" + denominator; } return numerator + "/" + denominator; } return "0"; } return "ERROR"; } }
package siZe3; public class MyException extends Exception { public MyException(String msg) { // TODO Auto-generated constructor stub super(msg); } }
package siZe3; import java.util.Stack; public class ShiTi { private int id; private String tiMu;// 题目 private String answer;// 答案 private String calculateOrder;// 运算式计算顺序,(后缀表达式) private int countNumber;// 运算符个数 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTiMu() { return tiMu; } public void setTiMu(String tiMu) { this.tiMu = tiMu; try { expressCalculate(); } catch (MyException e) { // TODO Auto-generated catch block e.printStackTrace(); }// 计算答案 this.countNumber = (tiMu.split(" ").length + 1) / 2; } public String getAnswer() { return answer; } public void setAnswer(String answer) { this.answer = answer; } public String getCalculateOrder() { return calculateOrder; } public void setCalculateOrder(String calculateOrder) { this.calculateOrder = calculateOrder; } public int getCountNumber() { return countNumber; } public void setCountNumber(int countNumber) { this.countNumber = countNumber; } public ShiTi() { } // 表达式计算,参数为字符串类型的运算式 private void expressCalculate() throws MyException { if(this.tiMu == null) { throw new MyException("试题无效"); } String express = this.tiMu; Stack<String> num = new Stack<String>(); Stack<String> symbolS = new Stack<String>(); symbolS.push("#"); express += "#"; String order = ""; char ch; int i = 0; ch = express.charAt(i); while ((!symbolS.peek().equals("#")) || (ch != '#')) {// while循环开始 if (isNumber(ch)) {// 读到的不是空格,说明开始读运算数 String readNumStr = ""; while (true) { readNumStr += ch; ch = express.charAt(++i); if (ch == ' ' || ch == '#' || ch == ')') {// 读到的是空格,或,说明运算数结束 break; } } num.push(readNumStr); } else if (ch == ' ') { if ((i + 1) < express.length()) {// 未到字符串末尾 ch = express.charAt(++i); } }else {// 读到的是运算符 char compare = priorityCompare(symbolS.peek(), ch + ""); if (compare == '=') {// 若优先级相等,则说明ch是右括号,栈顶为左括号,此时将栈顶弹出,读取下一个字符 symbolS.pop(); ch = express.charAt(++i); } else if (compare == '>') {// ch的优先级小于栈顶的优先级,要说明栈顶的运算符应该先计算,所以应弹栈运算 // 弹出两个运算数,弹出一个运算符 String bStr = num.pop(); String aStr = num.pop(); String symbolT = symbolS.pop(); // 计算该字表达式 String c = yunSuan(aStr, bStr, symbolT); if (c.equals("ERROR")) {// 如果计算函数返回error则说明计算过程出现了负数,说明该运算式不符合要求,停止计算,计算结果为error,返回; this.answer = "ERROR"; return; } else {// 计算过程正常,则将计算结果压栈 order += aStr + "," + symbolT + "," + bStr + ",";// 将运算的子表达式加进运算顺序字符串中,操作数和操作符用逗号隔开 num.push(c); } } else if(compare == 'E') { this.answer = "ERROR"; return; } else {// 说明ch优先级大于栈顶元素的优先级,则应将ch压栈,读取下一个运算符 symbolS.push(ch + ""); if ((i + 1) < express.length()) { ch = express.charAt(++i); } } } } this.answer = num.pop(); this.calculateOrder = order; } // 判断ch是否为数字 private boolean isNumber(char ch) { if (ch >= '0' && ch <= '9') { return true; } return false; } /* * 子表达式计算,参数为两个运算数的字符串形式,和一个运算符,也为字符串类型 返回计算结果的字符串形式 * 如果减法运算出现负数,或除数为0,或分数的分母为0则返回ERROR * */ private String yunSuan(String aStr, String bStr, String symbol) throws MyException { if(aStr == null || bStr == null || symbol == null) { throw new MyException("子表达式出现错误!"); } int adivIndex = aStr.indexOf("/"); int bdivIndex = bStr.indexOf("/"); if ((adivIndex == -1) && (bdivIndex == -1)) {// a.b都是整数 int a = Integer.parseInt(aStr); int b = Integer.parseInt(bStr); switch (symbol.charAt(0)) { case '+': return a + b + ""; case '-': { if (a < b) { return "ERROR"; } return a - b + ""; } case '*': { return a * b + ""; } case '/': { if (b == 0) { return "ERROR"; } else if (a % b == 0) { return a / b + ""; } return new FenShu(a, b).toString(); } default: return "ERROR"; } } else {// a,b中存在分数,则将a,b都当做分数进行运算 FenShu a = new FenShu(aStr); FenShu b = new FenShu(bStr); switch (symbol.charAt(0)) { case '+': return a.add(b).toString(); case '-': { FenShu c = a.subtract(b); if(c.getNumerator() < 0) { return "ERROR"; } return c.toString(); } case '*': return a.multiply(b).toString(); case '/': return a.divide(b).toString(); default: return "ERROR"; } } } // 判断运算符优先级 private char priorityCompare(String a, String b) { char[][] priority = { { '>', '>', '<', '<', '<', '>', '>' }, { '>', '>', '<', '<', '<', '>', '>' }, { '>', '>', '>', '>', '<', '>', '>' }, { '>', '>', '>', '>', '<', '>', '>' }, { '<', '<', '<', '<', '<', '=', '>' }, { '>', '>', '>', '>', ' ', '>', '>' }, { '<', '<', '<', '<', '<', ' ', '=' } }; int a_index = index_symbol(a); int b_index = index_symbol(b); if(a_index == -1 || b_index == -1) { return 'E'; } return priority[a_index][b_index]; } // 获取运算符对应的下标 private int index_symbol(String a) { String p = "+-*/()#"; // System.out.println("判断运算符对应的下标:" + a); return p.indexOf(a); } }
package siZe3; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; //试题数据库操作类,即对数据库进行增删改查的操作的类 public class ShiTiDAO { private String INSERT_SQL = "insert into shiTiKu01(tiMu,answer,calculateOrder) values(?,?,?)"; private String SELECTBYNUMBERCOUNT_SQL = "select * from shiTiKu01 where numberCount=?"; private String SELECTALL = "select * from shiTiKu01"; // 向数据库中插入一条记录 public void insert(ShiTi stb) throws SQLException, MyException { if(stb == null) { throw new MyException("试题无效!"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; conn = DBUtil.getDBConnection();// 获取连接 pstmt = conn.prepareStatement(INSERT_SQL);// 获取操作对象 // 设置字段值 pstmt.setString(1, stb.getTiMu()); pstmt.setString(2, stb.getAnswer()); pstmt.setString(3, stb.getCalculateOrder()); //pstmt.setInt(4, stb.getCountNumber()); // 执行 pstmt.executeUpdate(); // 释放资源 DBUtil.closeRS(conn, pstmt, rs); } // 向数据库中插入多条记录,参数为list public void insert(List<ShiTi> list) throws SQLException, MyException { if(list == null) { throw new MyException("试题无效!"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; conn = DBUtil.getDBConnection();// 获取连接 pstmt = conn.prepareStatement(INSERT_SQL);// 获取操作对象 // 设置字段值 for (ShiTi stb : list) { pstmt.setString(1, stb.getTiMu()); pstmt.setString(2, stb.getAnswer()); pstmt.setString(3, stb.getCalculateOrder()); //pstmt.setInt(4, stb.getCountNumber()); pstmt.executeUpdate(); } // 执行 // 释放资源 DBUtil.closeRS(conn, pstmt, rs); } // 根据运算数个数查询,返回结果为list public List<ShiTi> selectByNumbercount(int count) throws SQLException, MyException { if(count < 2) { throw new MyException("运算数个数应大于等于2"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; List<ShiTi> list = new ArrayList<ShiTi>(); conn = DBUtil.getDBConnection();// 获取连接 pstmt = conn.prepareStatement(SELECTBYNUMBERCOUNT_SQL);// 获取操作对象 // 设置字段值 pstmt.setInt(1, count); // 执行 rs = pstmt.executeQuery(); // 结果处理 ShiTi stb = null; while (rs.next()) { stb = new ShiTi(); stb.setTiMu(rs.getString("tiMu")); stb.setAnswer(rs.getString("answer")); stb.setCalculateOrder(rs.getString("calculateOrder")); stb.setCountNumber(rs.getInt("numberCount")); list.add(stb); } // 释放资源 DBUtil.closeRS(conn, pstmt, rs); return list; } //查询数据库中的全部记录 public List<ShiTi> selectAll() throws SQLException { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; List<ShiTi> list = new ArrayList<ShiTi>(); conn = DBUtil.getDBConnection();// 获取连接 pstmt = conn.prepareStatement(SELECTALL);// 获取操作对象 // 执行 rs = pstmt.executeQuery(); // 结果处理 ShiTi stb = null; while (rs.next()) { stb = new ShiTi(); stb.setTiMu(rs.getString("tiMu")); stb.setAnswer(rs.getString("answer")); stb.setCalculateOrder(rs.getString("calculateOrder")); stb.setCountNumber(rs.getInt("numberCount")); list.add(stb); } // 释放资源 DBUtil.closeRS(conn, pstmt, rs); return list; } }
package siZe3; import java.util.Random; //试题类, /* * 方法有:生成一个试题,计算试题答案, * * */ public class ShiTiOperator { // 获取一个运算式 public static void main(String[] args) { ShiTi a = new ShiTi(); a.setTiMu("4 + 2 / 3 - 1");//设置题目a System.out.println("答案为:" + a.getAnswer()); // ShiTi b = new ShiTi(); // b.setTiMu("2 + 1 + 4 + 3");//设置题目b // System.out.println("是否重复判断结果为:" + calculateOrderSame(a, b)); } public static ShiTi getExpress(int maxNum, int hasKuoHao, int type) throws MyException { if(maxNum <= 0) { throw new MyException("最大数值应为正数"); } ShiTi stb = new ShiTi(); Random rd = new Random(); char[] fuHao = { '+', '-', '*', '/' }; while (true) { int[] bracket = null;// 存储括号位置 int expressLength = rd.nextInt(3) + 2;// 随机生成一个2~4之间的整数作为该运算式的运算数的个数 stb.setCountNumber(expressLength); String[] number = new String[expressLength];// 存储运算数的数组 String[] symbol = new String[expressLength - 1];// 存储运算符的数组 String express = ""; number[0] = getOperatorNumber(type, maxNum); for (int i = 0; i < expressLength - 1; i++) { symbol[i] = fuHao[rd.nextInt(4)] + "";// 生成运算符 number[i + 1] = getOperatorNumber(type, maxNum); } if (hasKuoHao == 1) { // 需要加括号 bracket = randomAddBracket(expressLength); } // 构建表达式 for (int i = 0; i < expressLength; i++) { // 添加左括号 if (hasKuoHao == 1) { for (int j = 0; j < bracket[i]; j++) { express += "("; } } express += number[i];// 加上运算数 // 添加右括号 if (hasKuoHao == 1) { for (int j = 0; j > bracket[i]; j--) { express += ")"; } } if (i != expressLength - 1) { express += " " + symbol[i] + " ";// 加运算符,并在两侧加空格来与运算数分隔 } } stb.setTiMu(express); if (!(stb.getAnswer().equals("ERROR"))) { // System.out.println("生成的运算式为:" + express + "=" + result[0]); return stb; } } } // 随机生成括号,参数为运算式的运算数的个数 private static int[] randomAddBracket(int length) throws MyException { if(length <= 1) { throw new MyException("运算式长度不能小于2"); } int[] brackets = new int[length]; for (int i = 0; i < brackets.length; i++) brackets[i] = 0; Random rd = new Random(); for (int i = 2; i < length; i++) {// 添加的括号长度(括号包围的运算数的个数) for (int j = 0; j < length - i + 1; j++) { int t = rd.nextInt(2);// 随机生成0或1,0代表不加括号,1代表加括号 if (t == 1) { if (brackets[j] >= 0 && brackets[j + i - 1] <= 0) {// 要加的括号的第一个运算数周围没有右括号,且 // 最后一个运算数周围没有左括号 int counteract1 = 0,counteract2 = 0,counteract3 = 0; for (int k = j; k < j + i; k++) {// 将要加的括号之间的所有运算数对应的brackets相加, // 如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 counteract1 += brackets[k]; } for (int k = 0; k < j - 1; k++) {// 将要加的括号之前的所有运算数对应的brackets相加, // 如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 counteract2 += brackets[k]; } for (int k = j + i; k < length; k++) {// 将要加的括号之后的所有运算数对应的brackets相加, // 如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象 counteract3 += brackets[k]; } if (counteract1 == 0 && counteract2 == 0 && counteract3 == 0) { brackets[j]++; brackets[j + i - 1]--; j += i; } } } } } return brackets; } // 随机生成一个运算数( type==0代表生成整数,type==1代表生成真分数,maxNum代表数值范围 0~(maxNum-1) ) private static String getOperatorNumber(int type, int maxNum) throws MyException { if(maxNum <= 0) { throw new MyException("最大数值应为正数"); } Random rd = new Random(); int a; while (true) { a = rd.nextInt(maxNum); if (type == 0) {// 随机生成一个整数 return "" + a; } else {// 随机生成一个真分数 if (a == 0) { continue; } int b = rd.nextInt(a); FenShu c = new FenShu(b, a); return c.toString(); } } } //-------------------------------------------------- public static boolean calculateOrderSame(ShiTi a, ShiTi b) throws MyException { if(a == null || b == null) { throw new MyException("试题无效!"); } //比较两个运算式的运算数个数 if(a.getCountNumber() != b.getCountNumber()) { return false; } //比较两运算式的答案是否相同 if(!a.getAnswer().equals(b.getAnswer())) { return false; } // 取出运算式的运算顺序字符串, String aorder = a.getCalculateOrder(); String border = b.getCalculateOrder(); // 将a,b运算式的运算顺序字符串进行分割,按序取出每一个运算数和运算符 String[] asplit = aorder.split(","); String[] bsplit = border.split(","); int n = a.getCountNumber() - 1;//共有n组子表达式 for(int i = 0;i < n;i++) { //取a运算式该子表达式的两个运算数a1,a2,运算符af,运算结果ar String a1 = asplit[0 + i * 3]; String af = asplit[1 + i * 3]; String a2 = asplit[2 + i * 3]; //取b运算式该子表达式的两个运算数b1,b2,运算符bf,运算结果br String b1 = bsplit[0 + i * 3]; String bf = bsplit[1 + i * 3]; String b2 = bsplit[2 + i * 3]; if(af.equals(bf)) { //两子表达式符号相同 if(a1.equals(b1) && a2.equals(b2)) { continue;//该子表达式相同,继续判断下一个子表达式 } else if( (af.equals("+") || af.equals("*")) && a1.equals(b2) && a2.equals(b1) ) { continue;//该子表达式相同,继续判断下一个子表达式 } else { return false; } } else { return false; } } return true; } //-------------------------------------------------- }
package siZe3; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.List; /* * 随机生成四则运算式3,2017年03月13日20:20:18 * * */ import java.util.Scanner; public class SiZe3 { static Scanner scan = new Scanner(System.in); public static void main(String[] args) throws FileNotFoundException { // TODO Auto-generated method stub menu(); scan.close(); } public static void menu() { System.out.println("1、判断文件中的题目及统计;2、随机生成题目"); int p = scan.nextInt(); if (p == 1) { System.out.println("请输入题目文件路径:"); String tiMuFileName = scan.next(); System.out.println("请输入答案文件路径:"); String answerFileName = scan.next(); try { panDuanTiMuFromFile(new File(tiMuFileName), new File(answerFileName)); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { System.out.println("0、整数式 1、分数式"); int type = scan.nextInt(); System.out.println("生成的运算式个数:"); int n = scan.nextInt(); System.out.println("是否有括号(1有,0没有)"); int hasKuoHao = scan.nextInt(); System.out.println("数值范围(最大数)"); int maxNum = scan.nextInt(); Date beginDate = new Date(); Date endDate = null; List<ShiTi> list = null; try { list = createYunSuanShi(hasKuoHao, maxNum, n, type); } catch (MyException e1) { // TODO Auto-generated catch block e1.printStackTrace(); System.out.println(e1); } // List<ShiTi> list2 = null; //List<ShiTiBean> list = createYunSuanShi(1, 20, 1000, 0); //将该list保存到数据库 ShiTiDAO st = new ShiTiDAO(); try { st.insert(list); endDate = new Date(); // list2 = st.selectAll(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MyException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(e); } //比较从数据库读出来的数据与原数据是否相同 // boolean same = true; // if(list.size() == list2.size()) // { // for(int i = 0;i < list.size();i++) // { // ShiTi a = list.get(i); // ShiTi b = list.get(i); // if( !( (a.getTiMu().equals(b.getTiMu())) && (a.getAnswer().equals(b.getAnswer())) && (a.getCalculateOrder().equals(b.getCalculateOrder())) && (a.getCountNumber() == b.getCountNumber()))) // { // same = false; // break; // } // } // } // else // { // same = false; // } //显示试题信息 for (int i = 0; i < list.size(); i++) { ShiTi s = list.get(i); System.out.println((i + 1) + " : " + s.getTiMu() + " = " + s.getAnswer());// + " 运算顺序:" //+ s.getCalculateOrder() + " 运算数个数:" + s.getCountNumber()); } System.out.println("生成" + n + "个运算式并将数据插入到数据库共耗时:" + (endDate.getTime() - beginDate.getTime()) + "ms"); // System.out.println("从数据库读取出的数据与原数据是否相同:" + same); // System.out.println(""); //读取数据库中的全部试题 // System.out.println("生成" + n + "个运算式共耗时:" + (endDate.getTime() - beginDate.getTime()) + "ms"); } } //从文件中读取的题目和答案,判断答案是否正确,并将统计结果输出到文件Grade.txt文件 public static void panDuanTiMuFromFile(File tiMu, File answer) throws IOException { BufferedReader tiMuBR = new BufferedReader(new FileReader(tiMu)); BufferedReader answerBR = new BufferedReader(new FileReader(answer)); List<Integer> rightIndexList = new ArrayList<Integer>(); List<Integer> wrongIndexList = new ArrayList<Integer>(); int num = Integer.parseInt(tiMuBR.readLine()); for (int i = 0; i < num; i++) { ShiTi stb = new ShiTi(); String tiMuR = tiMuBR.readLine(); String[] tiMuRsz = tiMuR.split(":"); int index = Integer.parseInt(tiMuRsz[0]); stb.setTiMu(tiMuRsz[1]); String answerR = answerBR.readLine(); if (stb.getAnswer().equals(answerR)) { // 文件中的答案正确 // 将该题号添加到rightIndexList中 rightIndexList.add(index); } else { // 答案不正确,将该题号添加到wrongIndexList中 wrongIndexList.add(index); } } // 构造输出流对象,将结果信息输出到文件Grade.txt PrintWriter pw = new PrintWriter(new File("Grade.txt")); pw.print("Correct:" + rightIndexList.size() + "("); for (int i = 0; i < rightIndexList.size(); i++) { pw.print(rightIndexList.get(i)); if (i != (rightIndexList.size() - 1)) { pw.print(","); } else { pw.println(")"); } } pw.print("Wrong:" + wrongIndexList.size() + "("); for (int i = 0; i < wrongIndexList.size(); i++) { pw.print(wrongIndexList.get(i)); if (i != (wrongIndexList.size() - 1)) { pw.print(","); } else { pw.println(")"); } } System.out.println("已将统计结果输出到文件Grade.txt"); // 释放资源 pw.close(); answerBR.close(); tiMuBR.close(); } // 生成整数计算式添加限制条件,type为运算式类型 0代表整数式,1代表真分数式 public static List<ShiTi> createYunSuanShi(int hasKuoHao, int maxNum, int n, int type) throws MyException { int i = 0; if(n <= 0) { throw new MyException("运算数个数设置错误,应为正数"); } List<ShiTi> list = new ArrayList<ShiTi>(); ShiTi stb = null; // ShiTiDAO std = new ShiTiDAO(); while (i < n) { stb = ShiTiOperator.getExpress(maxNum, hasKuoHao, type); // 检验重复 boolean chongFu = false; for (int j = 0; j < i; j++) { ShiTi t = list.get(j); if (ShiTiOperator.calculateOrderSame(stb, t)) { chongFu = true; System.out.println("出现重复:计算式一:" + t.getTiMu() + " = " + t.getAnswer() + " 运算顺序:" + t.getCalculateOrder() + " 运算数个数:" + t.getCountNumber()); System.out.println("出现重复:计算式二:" + stb.getTiMu() + " = " + stb.getAnswer() + " 运算顺序:" + stb.getCalculateOrder() + " 运算数个数:" + stb.getCountNumber()); System.out.println(" "); break; } } if (chongFu == false) { list.add(stb); i++; } } return list; } }
三、运行结果截图
四、编程总结分析
对于这样复杂的JAVA程序来说,要重点把它细分为几个JAVA类,进行封装,各自承担不同的任务,最后在主类中调用。
PSP0记录开发过程中的时间记录日志
任务开始之前:
任务结束:
在个人项目中学到了什么:
真的是要去分析程序的各个功能点,然后封装成各个类。