利用栈计算表达式应用——给小朋友出题并计算正答率(并保存数据)
(一)效果展示
题库XX.txt
答题过程
存储记录文件 xx.txt
(二)将所需要用到的+,-,等符号封装,然后写几个判断方法
1 public char[] op = {'+','-','*','/','(',')'}; 2 public String[] strOp = {"+","-","*","/","(",")"}; 3 public boolean isDigit(char c){ 4 if(c>='0'&&c<='9'){ 5 return true; 6 } 7 return false; 8 } 9 public boolean isOp(char c){ 10 for(int i=0;i<op.length;i++){ 11 if(op[i]==c){ 12 return true; 13 } 14 } 15 return false; 16 } 17 public boolean isOp(String s){ 18 for(int i=0;i<strOp.length;i++){ 19 if(strOp[i].equals(s)){ 20 return true; 21 } 22 } 23 return false; 24 }
(三)因为要将题目都转化成String类型进行处理,所以要处理计算式
1 public List<String> work(String str){ 2 List<String> list = new ArrayList<String>(); 3 char c; 4 5 //StringBuilder 与StringBuffer本质上没什么区别,主要是StringBuilder去掉了保护线程安全那部分的开销 6 //append()方法用于字符的拼接 7 StringBuilder sb = new StringBuilder(); 8 for(int i=0;i<str.length();i++){ 9 c = str.charAt(i); 10 if(isDigit(c)){ 11 sb.append(c); 12 } 13 if(isOp(c)){ 14 if(sb.toString().length()>0){ 15 list.add(sb.toString()); 16 sb.delete(0, sb.toString().length()); 17 } 18 //c+""为的是符合list<String>的存储参数String类型 19 list.add(c+""); 20 } 21 } 22 //将最后sb中的 数据存到List中并且 清空sb 23 if(sb.toString().length()>0){ 24 list.add(sb.toString()); 25 sb.delete(0, sb.toString().length()); 26 } 27 return list; 28 } 29 public void printList(List<String> list){ 30 for(String o:list){ 31 System.out.print(o+" "); 32 } 33 }
(四)将中缀表达式转化为后缀表达式,然后利用栈进行计算
public List<String> InfixToPostfix(List<String> list){ List<String> Postfixlist = new ArrayList<String>();//存放后缀表达式 Stack<String> stack = new Stack<String>();//暂存操作符 for(int i=0;i<list.size();i++){ //按优先级压栈 String s = list.get(i); if(s.equals("(")){ stack.push(s); }else if(s.equals("*")||s.equals("/")){ stack.push(s); }else if(s.equals("+")||s.equals("-")){ if(!stack.empty()){ while(!(stack.peek().equals("("))){ Postfixlist.add(stack.pop()); if(stack.empty()){ break; } } stack.push(s); }else{ stack.push(s); } }else if(s.equals(")")){ while(!(stack.peek().equals("("))){ Postfixlist.add(stack.pop()); } stack.pop(); }else{ Postfixlist.add(s); } if(i==list.size()-1){ while(!stack.empty()){ Postfixlist.add(stack.pop()); } } } return Postfixlist; } /** * 后缀表达式计算 */ public int doCal(List<String> list){ Stack<Integer> stack = new Stack<Integer>(); for(int i=0;i<list.size();i++){ String s = list.get(i); int t=0; if(!isOp(s)){ t = Integer.parseInt(s); stack.push(t); }else{ if(s.equals("+")){ int a1 = stack.pop(); int a2 = stack.pop(); int v = a2+a1; stack.push(v); }else if(s.equals("-")){ int a1 = stack.pop(); int a2 = stack.pop(); int v = a2-a1; stack.push(v); }else if(s.equals("*")){ int a1 = stack.pop(); int a2 = stack.pop(); int v = a2*a1; stack.push(v); }else if(s.equals("/")){ int a1 = stack.pop(); int a2 = stack.pop(); int v = a2/a1; stack.push(v); } } } return stack.pop(); }
(五)读取文件内容的方法
1 public String[] getFile(String pathName) throws Exception { 2 // 【1】先创建一个File的实体对象 3 File file = new File(pathName); 4 5 if (!file.exists()) 6 throw new RuntimeException("找不到文件!"); 7 // 【2】加载BUfferedReader流 8 BufferedReader br = new BufferedReader(new FileReader(file)); 9 String str; 10 String []arr = null; 11 // 【3】一行一行读取 12 while ((str = br.readLine()) != null) { 13 14 15 // 文件中数据的分割我用的是‘,’具体根据自己的情况调用下面的split()函数 16 arr = str.split(","); 17 18 } 19 return arr; 20 }
(六)将记录存储到文件中的方法
// 将数据存储到文件中 public void toFile(String path,int sumOfQ,String []wqs,int []Wresult,String TL,int []result,int[]arr) throws Exception { File file = null; FileWriter fWriter = null; file = new File(path); try { if (!file.exists()) { System.out.println("要读入数据的文件不存在"); } fWriter = new FileWriter(file); fWriter.write("答题的数量:"+sumOfQ+"\n"); fWriter.write("相应题目:\n"); for (int i = 0; i < sumOfQ; i++) { fWriter.write(wqs[arr[i]]+"\n"); } fWriter.write("你当时的提交答案: "); for (int i = 0; i < Wresult.length; i++) { fWriter.write(Wresult[i]+" "); } fWriter.write("\n"); fWriter.write("本次答题的正答率: "+TL+"\n"); fWriter.write("本次题目的标准答案: "); for (int i = 0; i < result.length; i++) { fWriter.write(result[i]+" "); } fWriter.write("\n"); fWriter.flush(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { if (fWriter != null) { fWriter.close(); } } }
(七)将标准答案与用户输入答案进行对比,并计算出正答率的方法
1 // 用来对比用户的答案和标准答案之间的方法 2 //参数为用户输入的答案数组 3 public String compare(int[] a,int[] results,int sumOfQ) { 4 double t = 0; 5 //将答错的题的序号保存到list中方便调用 6 List<Integer> falseQ = new ArrayList<Integer>(); 7 for (int i = 0; i < results.length; i++) { 8 if (a[i] == results[i]) 9 t++; 10 else { 11 12 falseQ.add(Integer.valueOf(i + 1)); 13 } 14 } 15 16 if (falseQ.isEmpty()) { 17 System.out.println("恭喜你,答对了所有题目!"); 18 } else { 19 System.out.print("答题完成,存在问题的序号为:"); 20 for (int i = 0; i < falseQ.size(); i++) { 21 System.out.print(falseQ.get(i) + " "); 22 } 23 } 24 System.out.println(); 25 System.out.println("你的正答率为:" + (DF_00(Double.valueOf(t / sumOfQ * 100))) + "%"); 26 27 return String.valueOf(DF_00(Double.valueOf(t / sumOfQ * 100)))+"%"; 28 }
(八)对各种数据和运算结果进行规范的方法
1 public static double DF_00(Double b) { 2 //调用DecimalForamt类的实例对象 对数据进行位数规范, 3 //因为规范完后的数据我还要进行操作,我又将它进行强制转化 4 DecimalFormat dFormat = new DecimalFormat("#.00"); 5 return Double.parseDouble(dFormat.format(b)); 6 }
(九)用来随机出题的方法
1 public int[] suiji(int sumOfQ,String[]wqs) { 2 3 int[] arr = new int[sumOfQ]; 4 arr[0] = (int) (Math.floor(Math.random() * (wqs.length))); 5 boolean isSame = true; 6 int j=0; 7 while (isSame == true) { 8 9 int suiji = (int) (Math.floor(Math.random() * (wqs.length))); 10 for (int i = 0; i < arr.length; i++) { 11 if (arr[i] == suiji) { 12 isSame = true; 13 break; 14 } else { 15 isSame = false; 16 continue; 17 } 18 19 } 20 if (!isSame) { 21 22 arr[j] = suiji; 23 j++; 24 isSame = true; 25 } 26 27 if (j == 3) { 28 break; 29 } 30 } 31 return arr; 32 }
(十)用来让用户输入答案,并保存答案的方法
//用来让用户输入答案,并且保存用户输入的答案 public int [] Wresult(int sumOfQ) { System.out.println("请依次输入你的答案:"); Scanner sc = new Scanner(System.in); String nextLine = sc.nextLine(); String[] temp = nextLine.split(" "); int[] Wresult = new int[sumOfQ]; for (int i = 0; i < temp.length; i++) { int wResult = Integer.parseInt(temp[i]); Wresult[i] = wResult; } return Wresult; }
(十一)测试
1 public static void main(String[] args) { 2 // TODO Auto-generated method stub 3 4 LV lt = new LV(); 5 6 // 获取题目内容 7 try { 8 wqs = lt.getFile("数据结构第二阶段.txt"); 9 } catch (Exception e) { 10 // TODO Auto-generated catch block 11 e.printStackTrace(); 12 } 13 14 System.out.println("请输入题目数目:"); 15 Scanner scanner = new Scanner(System.in); 16 int sumOfQ = scanner.nextInt(); 17 18 arrs = lt.suiji(sumOfQ, wqs); 19 20 21 22 results = new int[sumOfQ]; 23 for (int i = 0; i < sumOfQ; i++) { 24 String str = wqs[arrs[i]]; 25 System.out.println((i + 1) + ": " + str); 26 List<String> list = lt.work(str); 27 List<String> list2 = lt.InfixToPostfix(list); 28 results[i] = lt.doCal(list2); 29 } 30 31 32 33 int[] Wresult = lt.Wresult(sumOfQ); 34 35 36 String TL = lt.compare(results, Wresult, sumOfQ); 37 38 39 System.out.println("正确答案为:"); 40 for (int i = 0; i < results.length; i++) { 41 System.out.println((i + 1) + ": " + results[i]); 42 } 43 44 45 System.out.println("本次答题记录正在为您存储请稍后。。。。。"); 46 Thread thread = new Thread(); 47 48 try { 49 lt.toFile("inputFile.txt", sumOfQ, wqs, Wresult, TL, results,arrs); 50 } catch (Exception e1) { 51 // TODO Auto-generated catch block 52 e1.printStackTrace(); 53 } 54 55 try { 56 Thread.sleep(1000); 57 thread.start(); 58 System.out.println("记录已存储至inputFile.txt!"); 59 } catch (InterruptedException e) { 60 // TODO Auto-generated catch block 61 e.printStackTrace(); 62 } 63 64 65 }