个人作业1——四则运算题目生成程序(基于控制台)
Posted - Coding Never Ends -
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了个人作业1——四则运算题目生成程序(基于控制台)相关的知识,希望对你有一定的参考价值。
-
PSP2.1 Personal Software Process Stages Time Senior Student Time Planning 计划 360 420 · Estimate 估计这个任务需要多少时间 360 420 Development 开发 200 340 · Analysis 需求分析 (包括学习新技术) 20 40 · Design Spec 生成设计文档 15 25 · Design Review 设计复审 10 15 · Coding Standard 代码规范 5 5 · Design 具体设计 30 60 · Coding 具体编码 60 120 · Code Review 代码复审 40 60 · Test 测试(自我测试,修改代码,提交修改) 20 20 Reporting 报告 40 30 · 测试报告 20 15 · 计算工作量 30 10 · 并提出过程改进计划 70 25
- 因为针对的人群比较明确,所以涉及程序的时候应该对功能描述得清晰明了,能够使使用者一目了然。
- 保证程序运算逻辑正确是基本的要求,其次应该要做出优化,例如分数的显示,题目难度的设计等。
-
1 package com.uml.arithmetic; 2 3 import java.util.Random; 4 5 public class RandomMath { 6 7 private static String[] operate = new String[] { "+", "-", "×", "÷" }; // 运算符 8 static Random r = new Random(); 9 10 static String RandomMath(int nums) { 11 nums(nums); 12 /* 13 * 括号的位置 14 * 1. (a - b) - c - d = ? 15 * 2. (a - b - c) - d = ? 16 * 3. a - (b - c) - d = ? 17 * 4. a - (b - c - d) = ? 18 * 5. a - b - (c - d) = ? 19 * 其中“-”代表运算符 20 */ 21 String op = operate[r.nextInt(3)];// 防止出现假分数设置第二位运算符不能为“÷” 22 String tmp1[] = getOnce_new(nums);// 第一个式子 23 String tmp2[] = getOnce_new(nums);// 第二个式子 24 String quesStr = ""; 25 26 int temp = r.nextInt(5); 27 switch (temp) { // 括号的位置 28 case 0: 29 quesStr = "(" + arraytoString(tmp1) + ")" + op + arraytoString(tmp2) + "=?"; 30 break; 31 case 1: 32 quesStr = "(" + arraytoString(tmp1) + op + tmp2[0] + ")" + tmp2[1] + tmp2[2] + "=?"; 33 break; 34 case 2: 35 quesStr = tmp1[0] + tmp1[1] + "(" + tmp1[2] + op + tmp2[0] + ")" + tmp2[1] + tmp2[2] + "=?"; 36 break; 37 case 3: 38 quesStr = tmp1[0] + tmp1[1] + "(" + tmp1[2] + op + arraytoString(tmp2) + ")" + "=?"; 39 break; 40 case 4: 41 quesStr = arraytoString(tmp1) + op + "(" + arraytoString(tmp2) + ")" + "=?"; 42 break; 43 case 5: 44 quesStr = arraytoString(tmp1) + op + arraytoString(tmp2) + "=?"; 45 break; 46 } 47 48 return quesStr; 49 //} 50 } 51 52 /*产生一组两目运算式*/ 53 static String[] getOnce_new(int nums) { 54 // String temp = ""; 55 //System.out.println("MaxNum1: "+nums); 56 int[] numbers = nums(nums); // 操作数 57 String temp[] = new String[3]; 58 int num = numbers[r.nextInt(nums)]; 59 int num2 = numbers[r.nextInt(nums)]; 60 String op = operate[r.nextInt(4)]; 61 if (op == "÷") { // 除法运算保证结果是真分数 62 if (num >= 2) 63 num2 += num; 64 } 65 temp[0] = num + ""; 66 temp[1] = op; 67 temp[2] = num2 + ""; 68 69 return temp; 70 } 71 72 /*字符串数组转字符串*/ 73 static String arraytoString(String str[]){ 74 if(str == null) 75 return ""; 76 StringBuilder builder = new StringBuilder(); 77 for(int i=0; i<str.length; i++){ 78 builder.append(str[i]); 79 } 80 return builder.toString(); 81 } 82 static int[] nums(int nums){ 83 int[] numbers = new int[nums]; // 操作数 84 for (int i = 1; i <= nums; i++) { 85 numbers[i - 1] = i; 86 } 87 return numbers; 88 } 89 }
- 2. SolveQuestion类
- 主要用来将中缀表达式转换为后缀表达式,然后进行求值
-
package com.uml.arithmetic; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.junit.Test; public class SolveQuestion { /** * 提前将 符号的优先级定义好 */ private static final Map<Character, Integer> basic = new HashMap<Character, Integer>(); static { basic.put(\'-\', 1); basic.put(\'+\', 1); basic.put(\'×\', 2); basic.put(\'÷\', 2); basic.put(\'(\', 0);// 在运算中 ()的优先级最高,但是此处因程序中需要 故设置为0 } static String solve(String str) { str = str.substring(0, str.length() - 2); String ques = toSuffix(str); return dealEquation(ques); } /** * 将 中缀表达式 转化为 后缀表达式 */ static String toSuffix(String infix) { List<String> queue = new ArrayList<String>(); // 定义队列 用于存储 数字 以及最后的 // 后缀表达式 List<Character> stack = new ArrayList<Character>(); // 定义栈 用于存储 运算符 // 最后stack中会被 弹空 try { char[] charArr = infix.trim().toCharArray(); // 字符数组 用于拆分数字或符号 String standard = "×÷+-()"; // 判定标准 将表达式中会出现的运算符写出来 char ch = \'&\'; // 在循环中用来保存 字符数组的当前循环变量的 这里仅仅是初始化一个值 没有意义 int len = 0; // 用于记录字符长度 【例如100*2,则记录的len为3 到时候截取字符串的前三位就是数字】 for (int i = 0; i < charArr.length; i++) { // 开始迭代 ch = charArr[i]; // 保存当前迭代变量 if (Character.isDigit(ch)) { // 如果当前变量为 数字 len++; } else if (Character.isLetter(ch)) { // 如果当前变量为 字母 len++; } else if (ch == \'.\') { // 如果当前变量为 . 会出现在小数里面 len++; } else if (Character.isSpaceChar(ch)) { // 如果当前变量为 空格 // 支持表达式中有空格出现 if (len > 0) { // 若为空格 代表 一段结束 ,就可以往队列中 存入了 【例如100 * 2 // 100后面有空格 // 就可以将空格之前的存入队列了】 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); // 往 // 队列存入 // 截取的 // 字符串 len = 0; // 长度置空 } continue; // 如果空格出现,则一段结束 跳出本次循环 } else if (standard.indexOf(ch) != -1) { // 如果是上面标准中的 任意一个符号 if (len > 0) { // 长度也有 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); // 说明符号之前的可以截取下来做数字 len = 0; // 长度置空 } if (ch == \'(\') { // 如果是左括号 stack.add(ch); // 将左括号 放入栈中 continue; // 跳出本次循环 继续找下一个位置 } if (!stack.isEmpty()) { // 如果栈不为empty int size = stack.size() - 1; // 获取栈的大小-1 即代表栈最后一个元素的下标 boolean flag = false; // 设置标志位 while (size >= 0 && ch == \')\' && stack.get(size) != \'(\') { // 若当前ch为右括号,则 // 栈里元素从栈顶一直弹出,直到弹出到 // 左括号 queue.add(String.valueOf(stack.remove(size))); // 注意此处条件:ch并未入栈,所以并未插入队列中;同样直到找到左括号的时候,循环结束了,所以左括号也不会放入队列中【也就是:后缀表达式中不会出现括号】 size--; // size-- 保证下标永远在栈最后一个元素【栈中概念:指针永远指在栈顶元素】 flag = true; // 设置标志位为true 表明一直在取()中的元素 } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { // 若取得不是()内的元素,并且当前栈顶元素的优先级>=对比元素 // 那就出栈插入队列 queue.add(String.valueOf(stack.remove(size))); // 同样 // 此处也是remove()方法,既能得到要获取的元素,也能将栈中元素移除掉 size--; } } if (ch != \')\') { // 若当前元素不是右括号 stack.add(ch); // 就要保证这个符号 入栈 } else { // 否则就要出栈 栈内符号 stack.remove(stack.size() - 1); } } if (i == charArr.length - 1) { // 如果已经走到了 中缀表达式的最后一位 if (len > 0) { // 如果len>0 就截取数字 queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len + 1, i + 1))); } int size = stack.size() - 1; // size表示栈内最后一个元素下标 while (size >= 0) { // 一直将栈内 符号全部出栈 并且加入队列中 // 【最终的后缀表达式是存放在队列中的,而栈内最后会被弹空】 queue.add(String.valueOf(stack.remove(size))); size--; } } } } catch (Exception e) { System.out.println(e.getMessage()); } return queue.stream().collect(Collectors.joining(",")); // 将队列中元素以,分割 // 返回字符串 } /** * 将 后缀表达式 进行 运算 计算出结果 * * @param equation * @return */ public static String dealEquation(String equation) { String[] arr = equation.split(","); // 根据, 拆分字符串 List<String> list = new ArrayList<String>(); // 用于计算时 // 存储运算过程的集合【例如list中当前放置 // 100 20 5 / 则取出20/5 // 最终将结果4存入list // 此时list中结果为 100 4 】 try { for (int i = 0; i < arr.length; i++) { // 此处就是上面说的运算过程, // 因为list.remove的缘故,所以取出最后一个数个最后两个数 // 都是size-2 int size = list.size(); switch (arr[i]) { case "+": double a = Double.parseDouble(list.remove(size - 2)) + Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(a)); break; case "-": double b = Double.parseDouble(list.remove(size - 2)) - Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(b)); break; case "×": double c = Double.parseDouble(list.remove(size - 2)) * Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(c)); break; case "÷": double d = Double.parseDouble(list.remove(size - 2)) / Double.parseDouble(list.remove(size - 2)); list.add(String.valueOf(d)); break; default: list.add(arr[i]); break; // 如果是数字 直接放进list中 } } } catch (Exception e) { System.out.println(e.getMessage()); } DecimalFormat df = new DecimalFormat("0.00"); // 设置double类型小数点后位数格式 // df.format(Double.parseDouble(list.get(0))).toString(); return list.size() == 1 ? df.format(Double.parseDouble(list.get(0))).toString() : "运算失败"; // 最终list中仅有一个结果,否则就是算错了 } }
五、小结
本次实验做的不是很理想,只实现了随机生成四则运算以及计算求值的功能,题目查重,分数的转换等功能都没有完全实现。
但是关于解题给了我一个新思路,将普通的中缀表达式转换为后缀表达式,然后计算求值。这样就不用考虑括号的问题,能够节省很多步骤。
还是要多努力,寻找一些先进的算法,常使用二叉树来存储算式。
以上是关于个人作业1——四则运算题目生成程序(基于控制台)的主要内容,如果未能解决你的问题,请参考以下文章