1.项目需求

  a) 除了整数以外,还要支持真分数的四则运算。 (例如:  1/6 + 1/8 = 7/24)

  b) 让程序能接受用户输入答案,并判定对错。 最后给出总共 对/错 的数量。

  c) 逐步扩展功能和可以支持的表达式类型,最后希望能支持下面类型的题目 (最多 10 个运算符,括号的数量不限制)

    25 - 3 * 4 - 2 / 2 + 89 = ?
    1/2 + 1/3 - 1/4 = ? 
    (5 - 4 ) * (3 +28) =?

  d) 一次可以批量出 100 道以上的题目,保存在文本文件中, 并且保证题目不能重复,

2.项目实现

  a)开发环境

    开发工具:MyEclipse、jdk1.8、windows 7

    开发语言:Java

  b)项目设计

    1)主要UML图

    2)主要代码

      a.判断两个数是否互质

        

  1. 1 public static boolean isCoprime(int m,int n){
  2. 2 int a=0;
  3. 3 int b=0;
  4. 4 int c=0;
  5. 5 if(m > n) {
  6. 6 a = m;
  7. 7 b = n;
  8. 8 }else{
  9. 9 a=n;
  10. 10 b=m;
  11. 11 }
  12. 12 while((c = a % b) != 0) {
  13. 13 a = b;
  14. 14 b = c;
  15. 15 }
  16. 16 if(b==1){
  17. 17 return true;
  18. 18 }
  19. 19 return false;
  20. 20 }

    b.分数约分

  1. /**
  2. * @param exp 单个分数表达式
  3. * @returned String 返回约分后的分数表达式
  4. * */
  5. public static String afterSimplify(String exp){
  6. String[] num=exp.split("/");
  7. int cop=Integer.parseInt(num[0]);//分子
  8. int deno=Integer.parseInt(num[1]);//分母
  9. if(cop==0){//分子为0
  10. return "0";
  11. }
  12. int max=0;
  13. while(max!=1){
  14. max=maxMultiple(cop, deno);//返回cop、deno的最大公约数
  15. cop/=max;
  16. deno/=max;
  17. }
  18. if(deno==1){
  19. return cop+"";//分数值为1
  20. }else{
  21. return cop+"/"+deno;//化简后的分数
  22. }
  23. }

    c.中缀表达式转化为后缀表达式

  1. /**
  2. * @param infix 中缀表达式
  3. * @returned String 后缀表达式
  4. * */
  5. public static String infix2postfix(String infix){
  6. String postfix="";
  7. int length=infix.length();
  8. Stack st = new Stack();
  9. String c;
  10. for (int i = 0; i < length; i++){
  11. c = infix.substring(i, i+1);
  12. if (c .equals("(")){
  13. st.push(c);
  14. }else if (c.equals(")")){
  15. while (!st.peek().equals("(")){
  16. postfix+= (st.pop()+"#");
  17. }
  18. st.pop();
  19. }else{
  20. try{
  21. Integer.parseInt(c);//判断读到的字符是否为数字
  22. for(int j=0;j<5;j++){//如读到数字,则继续向后读取,直到读到运算符为止
  23. String c_temp="";
  24. if((i+j+2)>length){//判断是否到达输入的字符串的结尾
  25. break;
  26. }
  27. c_temp=infix.substring(i+j+1,i+j+2);
  28. try {
  29. Integer.parseInt(c_temp);//判断独到的字符是否为数字
  30. c+=c_temp;
  31. continue;
  32. } catch (Exception e) {
  33. break;
  34. }
  35. }
  36. i+=(c.length()-1);
  37. postfix+= (c+"#");
  38. }catch(Exception e){
  39. while (!st.empty()&& (comparePri((String)st.peek(), c) >= 0)){
  40. postfix += (st.pop()+"#");
  41. }
  42. st.push(c);
  43. }
  44. }
  45. }
  46. while (!st.empty()){//输入栈中剩余的所有元素
  47. postfix +=(st.pop()+"#");
  48. }
  49. return postfix;
  50. }
  51.  
  52. /**
  53. *@param op1 op2 运算符
  54. *@return int op1、op2的优先级比较结果
  55. * */
  56. public static int comparePri(String op1, String op2){
  57. if (op1 .equals("(")){
  58. return -1;
  59. }else if (op1 .equals("+") || op1 .equals("-")){
  60. if (op2.equals("*") || op2.equals("/")){
  61. return -1;
  62. }
  63. }else if (op1 .equals("*") ||op1 .equals("/")){
  64. if (op2 .equals("+") || op2 .equals("-")){
  65. return 1;
  66. }
  67. }
  68. return 0;
  69. }

    d.表达式求值(整式和分式)

  1. /**
  2. * @param exp 四则运算表达式
  3. * @return 表达式元算结果的最简(分数)形式
  4. * */
  5. public String calculate(String exp){
  6. int a,b,result=0;
  7. String first,second,temp = "";
  8. int first_cop,first_deno,second_cop,second_deno;
  9. Stack s=new Stack();
  10. String[] c=exp.split("#");
  11. //分式求值
  12. if(exp.contains("/")){
  13. for(int i=0;i<c.length;i++){
  14. if(!(c[i].contains("+")||c[i].contains("-")||c[i].contains("*")||c[i].contains("/"))){
  15. s.push(c[i]+"/1");//将整数化为分母为1的分数形式
  16. continue;
  17. }else{
  18. second=(String) s.pop();
  19. first=(String) s.pop();
  20. first_cop=Integer.parseInt(first.split("/")[0]);//第一个分数的分子
  21. first_deno=Integer.parseInt(first.split("/")[1]);//第一个分数的分母
  22. second_cop=Integer.parseInt(second.split("/")[0]);//第二个分数的分子
  23. second_deno=Integer.parseInt(second.split("/")[1]);//第二个分数的分母
  24. if(c[i].equals("+")){//分数相加
  25. temp=(first_cop*second_deno+second_cop*first_deno)+"/"+(first_deno*second_deno);
  26. }else if(c[i].equals("-")){//分数相减
  27. temp=(first_cop*second_deno-second_cop*first_deno)+"/"+(first_deno*second_deno);
  28. }else if(c[i].equals("*")){//分数相乘
  29. temp=(first_cop*second_cop)+"/"+(first_deno*second_deno);
  30. }else if(c[i].equals("/")){//分数相除
  31. temp=(first_cop*second_deno)+"/"+(first_deno*second_cop);
  32. }
  33. s.push(temp);//将计算结果压入栈中
  34. }
  35. }
  36. //将最终结果约分后返回
  37. return Simplify.afterSimplify((String) s.pop());
  38. }else{
  39. //整式求值
  40. for(int i=0;i<c.length;i++){
  41. try{
  42. Integer.parseInt(c[i]);//判断是否为数字
  43. s.push(c[i]);
  44. continue;
  45. }catch(Exception e){
  46. b=Integer.parseInt((String) s.pop());
  47. a=Integer.parseInt((String) s.pop());
  48. if(c[i].equals("+")){
  49. result=a+b;
  50. }else if(c[i].equals("-")){
  51. result=a-b;
  52. }else if(c[i].equals("*")){
  53. result=a*b;
  54. }
  55. s.push(result+"");
  56. }
  57. }
  58. }
  59. //返回整数运算结果
  60. return result+"";
  61. }

    e.随机生成纯整式、纯分式、混合表达式

  1. if(type.equals("1")){//整式运算
  2. for (int i = 0; i < count; i++) {//生成count个正式
  3. questions.add(b.zhengshi(min, max));
  4. }
  5. }else if(type.equals("2")){//分式运算
  6. for (int i = 0; i < count; i++) {//生成count个分式
  7. questions.add(b.fenshi(deno));
  8. }
  9. }else if(type.equals("3")){//混合运算
  10. for (int i = 0; i < count; i++) {//生成count个混合元算表达式
  11. int length=r.nextInt(4)+3;//新加的符号个最最多为6个
  12. String op,exp="";
  13. for(int j=0;j<length;j++){
  14. op=ops[r.nextInt(2)];//随机选取运算符号 '+'或'*'
  15. if(op.equals("+")){
  16. if(r.nextInt(2)==1){
  17. exp=exp+b.zhengshu(min, max)+"+";
  18. }else{
  19. exp=exp+b.fenshu(deno)+"+";
  20. }
  21. }else if(op.equals("*")){
  22. if(exp.length()==0){
  23. exp=r.nextInt(9)+2+"+";
  24. }
  25. if(r.nextInt(2)==1){//随机选取整式或整数
  26. String item=b.zhengshi(min, max);
  27. while(item.contains("*")||item.contains("/")){
  28. item=b.zhengshi(min, max);
  29. }
  30. item="("+item+")";
  31. if((exp.substring(0,exp.length()-1).contains("+")||exp.substring(0,exp.length()-1).contains("-"))
  32. &&!exp.substring(0,exp.length()-1).contains("*")
  33. &&!exp.substring(0,exp.length()-1).contains("/")){
  34. exp="("+exp.substring(0,exp.length()-1)+")*"+item+"+";
  35. }else{
  36. exp=exp.substring(0,exp.length()-1)+"*"+item+"+";
  37. }
  38. }else{
  39. String item=b.zhengshu(min, max);
  40. if((exp.substring(0,exp.length()-1).contains("+")||exp.substring(0,exp.length()-1).contains("-"))
  41. &&!exp.substring(0,exp.length()-1).contains("*")
  42. &&!exp.substring(0,exp.length()-1).contains("/")){
  43. exp="("+exp.substring(0,exp.length()-1)+")*"+item+"+";
  44. }else{
  45. exp=exp.substring(0,exp.length()-1)+"*"+item+"+";
  46. }
  47. }
  48. }
  49. }
  50. if(!exp.equals("")&&(exp.subSequence(exp.length()-1, exp.length()).equals("+"))){
  51. exp=exp.substring(0,exp.length()-1);//剔除表达式末尾的加号
  52. }

  f.题目重复性检测

  1. public class CheckRepeat {
  2.  
  3. /**
  4. *@author GuoQingYun
  5. *@param list 以生成的题目组成的集合,集合呢各题均不重复
  6. *@param exp 新生成的待检测的表达式
  7. *@param BaseGenerator的对象
  8. *@return true-新生成的表达式与之前的重复 false-新生成的表达式与之前的不重复
  9. * */
  10. public static boolean check(List list,String exp,BaseGenerator b){
  11. String latterVal=b.calculate(Convert.infix2postfix(exp));
  12. List formorOperator=new ArrayList();
  13. List latterOperator=new ArrayList();
  14. List formorNumber=new ArrayList();
  15. List latterNumber=new ArrayList();
  16. for(int i=0;i<list.size();i++){
  17. //判断两个表达式的计算结果是否相等
  18. if(b.calculate(Convert.infix2postfix(list.get(i).toString())).equals(latterVal)){
  19. formorOperator=extractOperator(list.get(i).toString());
  20. latterOperator=extractOperator(exp);
  21. //判断两个表达式的运算符合是否完全一一匹配
  22. if(compare(formorOperator, latterOperator)){
  23. formorNumber=extractNumber(list.get(i).toString());
  24. latterNumber=extractNumber(exp);
  25. //判断两个表达式中包含的整数项是否完全一一匹配
  26. if(compare(formorNumber, latterNumber)){
  27. return true;
  28. }
  29. }
  30. }
  31. }
  32. return false;
  33. }
  34.  
  35. /**
  36. * @author GuoQingYun
  37. * @param exp -四则运算表达式
  38. * @return List -从表达式exp中分解出来的所有运算符的集合
  39. * */
  40. public static List extractOperator(String exp){
  41. List operator=new ArrayList();
  42. String c="";
  43. exp=exp.replace("(", "");//剔除掉表达中包含的括号
  44. exp=exp.replace(")", "");
  45. for (int i = 0; i < exp.length(); i++) {
  46. c=exp.substring(i,i+1);//逐个扫描表达式中的字符
  47. if(c.equals("+")||c.equals("-")||c.equals("*")||c.equals("/")){
  48. operator.add(c);
  49. }
  50. }
  51. return operator;
  52. }
  53.  
  54. /**
  55. * @author GuoQingYun
  56. * @param exp -四则运算表达式
  57. * @return List -从表达式exp中分解出来的所有整数的集合
  58. * */
  59. public static List extractNumber(String exp){
  60. List number=new ArrayList();
  61. String c="";
  62. exp=exp.replace("(", "");//剔除掉表达式中包含的括号
  63. exp=exp.replace(")", "");
  64. for (int i = 0; i < exp.length(); i++) {
  65. c=exp.substring(i,i+1);
  66. for(int j=0;j<5;j++){//如读到数字,则继续向后读取,直到读到运算符为止
  67. String c_temp="";
  68. if((i+j+2)>exp.length()){//判断是否到达输入的字符串的结尾
  69. break;
  70. }
  71. c_temp=exp.substring(i+j+1,i+j+2);
  72. try {
  73. Integer.parseInt(c_temp);//判断独到的字符是否为数字
  74. c+=c_temp;
  75. continue;
  76. } catch (Exception e) {
  77. break;
  78. }
  79. }
  80. i+=(c.length()-1);
  81. number.add("c");
  82. }
  83. return number;
  84. }
  85.  
  86. /**
  87. * @author GuoQingYun
  88. * @param formor -以存在的与其他表达式不重复的表达式中包含的运算符或整数的集合
  89. * @param latter -新生成的表达式中包含的运算符或整数的集合
  90. * @return boolean -true:formor与latter元素种类个元素个数完全匹配
  91. * -false:formor与latter元素种类个元素个数不完全匹配
  92. * */
  93. public static boolean compare(List formor,List latter){
  94. if(formor.size()!=latter.size()){
  95. //两个表达式运算符或整数项不是一一匹配
  96. return false;
  97. }else{
  98. for(int i=0;i<formor.size();i++){
  99. if(formor.contains(latter.get(i))){
  100. formor.remove(latter.get(i));//剔除掉已经比较过的项
  101. latter.remove(i);
  102. continue;
  103. }else{
  104. //两个表达式的运算符或整数项不是一一匹配
  105. return false;
  106. }
  107. }
  108. //两个表达式的运算符或整数项一一匹配
  109. return true;
  110. }
  111. }
  112. }

  c)测试结果

    1)整式运算

  2)分式运算

  3)混合运算

3.总结

  目前各项需求已基本达成,实验结果也比较令人满意。但也有不足之处,比如:题目生成规则优待有待改善等。这些问题将会在下一阶段逐步解决。

    

第一章-第一题(小学生四则运算)--By郭青云的更多相关文章

  1. Java程序设计(2021春)——第一章课后题(选择题+编程题)答案与详解

    Java程序设计(2021春)--第一章课后题(选择题+编程题)答案与详解 目录 Java程序设计(2021春)--第一章课后题(选择题+编程题)答案与详解 第一章选择题 1.1 Java与面向对象程 ...

  2. ASP.NET自定义控件组件开发 第一章 第一章:从一个简单的控件谈起

    第一章:从一个简单的控件谈起 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 ASP.NET自定义控件组件开发 第一章 第三 ...

  3. 第一章-第二题Unity3D游戏引擎相关--By林培文

    1) 此类软件是什么时候开始出现的, 这些软件是怎么说服你(陌生人)成为他们的用户的?  他们的目标都是盈利么?  他们的目标都是赚取用户的现金么?还是别的? 2004年,Unity3D诞生于丹麦哥本 ...

  4. 《python语言程序设计》_第一章编程题

    题目1.1 :显示"welcome to python " 答案:print('welcome to python') 题目1.2:显示"welcome to pytho ...

  5. jQuery框架分析第一章: 第一个匿名函数

    我的jQuery版本为1.7* 这个版本代码比之前的版本优化了很多,结构也清晰了不少,就用最新的吧. 打开jQuery源代码 首先你能看到所有代码被一个 (function(window,undefi ...

  6. c语言第一章第一节 认识变量

    声明:本人大一新生,闲着无聊..写写c语言教程..菜鸟一枚..大神勿喷!!! 接下来我们都用dev来进行编译..vc++太古老了,没提示功能,不好上手,并且老是出毛病..vs太大了,编个c不至于,运行 ...

  7. Zabbix简介(第一章第一节)

    Alexei Vladishev创建了Zabbix项目,当前处于活跃开发状态,Zabbix SIA提供支持. Zabbix是一个企业级的.开源的.分布式的监控套件 Zabbix可以监控网络和服务的监控 ...

  8. 【第一章第一回】BootStrap 简介

    Twitter Bootstrap 是目前最受欢迎的前端框架,它简洁.直观.移动优先.强悍的前端开发框架,让web开发更迅速.简单.基于HTML.CSS和Javascript. 为什么使用Bootst ...

  9. tensorflow2.0学习笔记第一章第一节

    一.简单的神经网络实现过程 1.1张量的生成 # 创建一个张量 #tf.constant(张量内容,dtpye=数据类型(可选)) import tensorflow as tf import num ...

随机推荐

  1. PHP控制输出不缓存头

    @header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); @header("Cache-Control: no-cache, ...

  2. PHP通用的XSS攻击过滤函数,Discuz系统中 防止XSS漏洞攻击,过滤HTML危险标签属性的PHP函数

    XSS攻击在最近很是流行,往往在某段代码里一不小心就会被人放上XSS攻击的代码,看到国外有人写上了函数,咱也偷偷懒,悄悄的贴上来... 原文如下: The goal of this function ...

  3. Linux C 字符串函数 strlen()、strcat()、strncat()、strcmp()、strncmp()、strcpy()、strncpy() 详解

      strlen(返回字符串长度) 表头文件 #include <string.h> 定义函数 size_t strlen(const char *s); 函数说明 strlen()用来计 ...

  4. C和指针 第三章 指针常量与常量指针

    c语言中声明常量的两种方式 const int value int const value 如果要声明常量的指针,即指向常量的指针,则可以参考上面的常量声明修改一下 const int *ptr in ...

  5. JS常见错误和分析

    列举一些在前端开发中遇到的一些错误信息和解决办法 错误信息 解决办法 Uncaught SyntaxError: Unexpected token o 使传入的字符串不是符合严格的JSON格式会抛出异 ...

  6. c/c++字符串定义及使用的对比

    c/c++中使用字符串的频率还是比较高的,下面就字符串的不同定义及其使用方法做一些对比 字符串一般有以下三种定义方法: 1.char *p="hello"; 2.char str[ ...

  7. October 23rd Week 44th Sunday 2016

    When ambition ends, happiness begins. 野心消亡之日,正是快乐破茧之时. No ambition, no annoyance. No ambition, no ac ...

  8. 【Jsoup网页解析】

    下载链接:http://jsoup.org/download 一.普通的请求方式(不带有cookie) 使用举例: 第一步: Connection conn=Jsoup.connect(url); 第 ...

  9. 【leetcode】Triangle (#120)

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...

  10. LCA + 树状数组 + 树上RMQ

    题目链接:http://poj.org/problem?id=2763 思路:首先求出树上dfs序列,并且标记树上每个节点开始遍历以及最后回溯遍历到的时间戳,由于需要修改树上的某两个节点之间的权值,如 ...