zoukankan      html  css  js  c++  java
  • 软件工程个人作业02

    程序设计思想:

             大体的思路还是不变,用生成随机数的方式生成若干个操作数,并且设置不同的参数来控制算术题的格式。但是这次的程序有了新的需求,而且新的需求实现过程更加困难,若是还是按照结构化思想来解决问题,将面临巨大的困难。所以,此次我用面向对象的方法来解决问题。

             将算术式封装成一个类,用字符串来存放一个算式。在这个类中,主要的问题还是如何构造算式。运算符、操作数和操作数的个数都可以用随机数来生成。但是,有三项难题需要解决:控制乘除有没有余数、加减有没有复数和控制有没有括号。要控制结果首先需要求出结果。现在已经不再是2个数一种运算符的求值了。多个数、多个优先级的运算符还有括号需要考虑,这是不可能在生成运算符和操作数时就可以得到正确结果的。所以我用到了数据结构中学到的一种算法——应用栈将中缀表达式化为后缀表达式,然后计算表达式结果。这个算法是去年学的,算法的步骤我还记忆犹新,但是实现的细节已经不太熟了,怎出这个算法也是花了我不少时间。第二个问题就是在支持余数的情况下怎么运算。整型的数据相除必然还会是整型数据,这样肯定得不到正确答案,所以为了解决这个问题,我还设计了另一个类Fraction类用来进行分数的运算符。将整数都化为分数,最后得到的结果就都是准确结果了。第三个问题,怎么让式子中包含括号。这个问题倒是真的难倒我了。想来想去我也只有一个办法,大致想法是先在第N个操作数前插入前括号,然后在第N+2个操作数后插入后括号,N为大于0小于操作数个数的一个随机数。这个方法基本上解决了问题,但是这只能为一个算式插入一对括号。

    程序源代码:

             因为怎个程序代码较长,所以以下仅展示核心类的实现。

      1 public class Equation {
      2 
      3     public static void main(String[] args) {
      4         // TODO Auto-generated method stub
      5         boolean flag = true;
      6         boolean sc = flag,fs=flag,kh=flag,fus=flag;
      7         int mun = 0,beg=0,end=100;
      8         
      9         Scanner scan = new Scanner(System.in);
     10         while(flag){
     11             try{
     12                 System.out.println("请输入表达式的个数:");
     13                 mun = scan.nextInt();
     14                 System.out.println("是否支持乘除法?(true/false)");
     15                 sc = scan.nextBoolean();
     16                 if(sc){
     17                     System.out.println("除法是否有余数?(true/false)");
     18                     fs = scan.nextBoolean();
     19                 }
     20                 System.out.println("是否有括号?(true/false)");
     21                 kh = scan.nextBoolean();
     22                 System.out.println("是否有负数?(true/false)");
     23                 fus = scan.nextBoolean();
     24                 flag = false;
     25             }catch(Exception e){
     26                 System.out.println("输入错误!请重新输入:");
     27                 flag = true;
     28             }
     29         }
     30         Equation array[] = new Equation[mun];
     31         for(int i = 0; i < mun; i++){
     32             array[i] =new Equation(beg,end,(int)(Math.random()*8)+2,sc,fs,kh,fus);
     33             System.out.println((i+1)+":"+array[i].getExpress()+"="+array[i].getValue());
     34         }
     35         scan.close();
     36     }
     37     public static final boolean 
     38         SUPPORT_FRACTION=true,            //支持分数
     39         NONSUPPORT_FRACTION=false,        //不支持分数
     40         NONSUPPORT_MINUS=false,            //不支持支持复数
     41         SUPPORT_MINUS=true,                //支持复数
     42         NONSUPPORT_MULTIPLICATION=false,//增加常量表示没有乘除法
     43         SUPPORT_MULTIPLICATION=true,    //表示含有乘除法
     44         NONSUPPORT_BRACKET=false,        //表示没有括号
     45         SUPPORT_BRACKET=true;            //表示带括号
     46     
     47 
     48     private String express,value;
     49     
     50 /**
     51  * 2017年3月10日修改记录:
     52  * 将原来用静态方法生成表达式的方法该为用构造方法生成表达式,更加符合面向对象的程序设计思路。
     53  * */    
     54     public Equation() {
     55         // TODO Auto-generated constructor stub
     56         this(0,100,10,true,true,true,true);
     57     }
     58     public Equation(int beg,int end,int n){
     59         this(beg,end,n,true,true,true,true);
     60     }
     61     public Equation(boolean mul,boolean fraction,boolean bra,boolean minus){
     62         this(0,100,10,mul,fraction,bra,minus);
     63     }
     64      public Equation(String e){
     65         express = e;
     66         try {
     67             evaluation(true,true);
     68         } catch (Exception e1) {
     69             // TODO Auto-generated catch block
     70             e1.printStackTrace();
     71         }
     72     }
     73     public Equation(int beg,int end,int m,boolean mul,boolean fraction,boolean bra,boolean minus)
     74     //beg表示操作数的最小值,end表示最大值,n表示操作数的个数,
     75     //mul表示是否支持乘除,bra是否支持括号,minus表示是否有负数,fraction表示是否支持分数
     76     {
     77         createExpress(beg,end,m,mul,fraction,bra,minus);
     78         //计算结果                
     79         boolean tag = true;
     80         while(tag){
     81             try {//如果计算结果时出现异常,将递归调用本方法为对象重新赋值
     82                 this.evaluation(fraction,minus);
     83                 tag = false;
     84             } catch (Exception e) {
     85                 createExpress(beg,end,m,mul,fraction,bra,minus);
     86                 tag = true;
     87             }
     88         }
     89     }
     90 
     91     //setter and get
     92     public String getExpress(){return express;}
     93     
     94     public void setExpress(String ex){express = ex;}
     95     
     96     public String getValue(){return value;}
     97     
     98     public String toString(){    
     99             return express+"="+value;
    100     }    
    101     public boolean equals(Equation another)//比较两个算式是否相同
    102     {
    103         String str1 = new String(this.express);
    104         String str2 = new String(another.express);
    105         str1.replaceAll(" ", "");
    106         str2.replaceAll(" ", "");
    107         if(str1.equals(str2))
    108             return true;
    109 
    110         return false;
    111     }
    112 
    113     private void createExpress(int beg,int end,int m,boolean mul,boolean fraction,boolean bra,boolean minus)
    114     //生成一个表达式
    115     {
    116         //数组operand存放express中的所有操作数
    117         int n = m;
    118         int operand[] = new int[n];
    119         //operator存放所有操作符
    120         char operator[] = new char[n];
    121         //oper存放可选择的操作符,如果mul为false,则没有乘除法
    122         char[] oper = {'+','-','*','/'};
    123         if(!mul) {oper[2]='+';oper[3]='-';}
    124         String ss=new String("");
    125         for(int i = 0; i < n; i++){
    126             operand[i] =(int) (Math.random()*(end-beg))+beg;
    127             operator[i]=oper[operand[i]%4];
    128             ss =ss+ operand[i]+operator[i];
    129         }
    130         
    131         if(bra&&((int)( Math.random()*100))>50){
    132             //在这里为express中插入一对括号
    133             
    134             int first = (int)(Math.random()*(n-1))+1;//括起来的第一个数
    135             int next = (int)(Math.random()*(n-1))+1;//括起来的最后一个数
    136             if(first > next){//如果第一个数比第二个数大,则交换两个数的值
    137                 first = first^next;
    138                 next = first^next;
    139                 first=first^next;
    140             }
    141             if(next-first >= 2){//如果next和first的差值小于2,则不执行以下步骤,因为括号中至少有两个数
    142                 //length记下表达式字符串的长度,j记下遍历字符串中数字的个数
    143                 int length = ss.length(),j=0;
    144                 //用字符串建立一个动态字符串。
    145                 StringBuffer temp = new StringBuffer(ss);
    146                 //开始循环遍历字符串
    147                 for(int i=0; i < length; i++){
    148                     char cc = temp.charAt(i);//取出下标为i的字符
    149                     if(first==1&&i==0)        //如果括号括起来的第一个数字为表达式中第一个操作数,在表达式最前面插入(
    150                         temp.insert(0, '(');
    151                     if(cc > '9' || cc < '0'){//如果当前字符是运算符字符
    152                         j++;                //表示刚刚遍历一个数字,所以j加一
    153                         if(j==first-1){        //如果j到达first的前一个位置,在当前字符的后面插入“(”
    154                             temp.insert(i+1, '(');i++;
    155                         }
    156                         if(j==next)            //如果j到达next的位置,在当前字符前面插入一个“)”
    157                             temp.insert(i, ')');
    158                     }
    159                 }
    160                 ss = temp.toString();//将动态字符串转换为普通字符串
    161             }
    162         }
    163         express = ss.substring(0, ss.length()-1);
    164     }
    165     private void evaluation(boolean yushu,boolean fushu) throws Exception//表达式求值
    166     {
    167         //申请一个存放分数的栈和一个存放操作符的栈
    168         java.util.Stack<Fraction> mStack = new java.util.Stack<Fraction>();
    169         java.util.Stack<Character> oStack= new java.util.Stack<Character>();
    170         
    171         String express = new String(this.express+"#");
    172         boolean flag = false;//旗帜变量标识上一个字符是否为数字字符
    173         int i = 0,//字符串的下标变量
    174                 len = express.length();//字符串的长度
    175         oStack.push('#');
    176         while(i < len){
    177             char ch  = express.charAt(i);//取出计算式中第i个字符
    178             //如果当前字符为空字符,跳过这个字符
    179             if(ch==' '||ch=='	'||ch=='
    ')i++;
    180             //如果是数字
    181             else if(ch >= '0' && ch <= '9'){
    182                 if(flag){
    183                     //如果前一个字符为数字字符,从mStack栈中弹出一个分数
    184                     //乘以10加上ch代表的数字后,再压入mStack栈中。
    185                     Fraction t1 = mStack.pop();
    186                     t1 = t1.multiply(10);
    187                     t1 = t1.add(ch-'0');
    188                     mStack.push(t1);
    189                     flag = true;//旗帜变量依然是true,标志当前字符为数字字符
    190                 }else{
    191                     //如果前一个字符不是数字字符,生成一个新的分数压入mStack中
    192                     mStack.push(new Fraction(ch-'0'));
    193                     flag = true;//标志当前字符为数字字符
    194                 }i++;//下一个字符
    195             }else{
    196                 switch(precede(oStack.peek(),ch)){
    197                 //比较oStack栈顶操作符的优先级和操作符ch的优先级
    198                 case '<'://栈顶操作符的优先级大于ch优先级
    199                     oStack.push(ch);
    200                     i++;break;
    201                 case '>':
    202                     //小于ch优先级,从分数栈中弹出两个分数按照运算符栈顶的操作运算,结果压入分数栈
    203                     Fraction b = mStack.pop();
    204                     Fraction a = mStack.pop();
    205                     Fraction c = calculate(a,oStack.pop(),b);
    206                     if(!yushu && c.getDenominator() > 1)
    207                         throw new Exception("计算过程出现余数!");
    208                     if(!fushu && c.lessThan(new Fraction(0)))
    209                         throw new Exception("计算过程出现负数!");
    210                     mStack.push(c);break;
    211                 case '=':
    212                     //优先级相等的情况
    213                     oStack.pop();//弹出运算符栈顶的运算符
    214                     i++;
    215                     break;
    216                 }
    217                 flag = false;//标志当前字符为运算符
    218             }
    219         }
    220         value=mStack.peek().toString();
    221         
    222     }
    223     private Fraction calculate//将分数pop和peek安照pop2代表的运算符计算
    224             (Fraction pop, Character pop2, Fraction peek)throws Exception
    225     {
    226         // TODO Auto-generated method stub
    227         if(pop2=='+')
    228             return pop.add(peek);
    229         else if(pop2=='-')
    230             return pop.reduce(peek);
    231         else if(pop2=='*')
    232             return pop.multiply(peek);
    233         else if(pop2=='/')
    234             return pop.divide(peek);
    235         return null;
    236     }
    237     private static char precede(char s,char t)//比较运算符s和t的优先级
    238     {
    239         char tag='<';                                      //临时变量,用来保存比较结果
    240         switch(s){
    241             case '+':
    242                 if(t == '*' || t == '/' || t == '(')
    243                     tag = '<';
    244                 else
    245                     tag = '>';
    246                 break;
    247             case '-':
    248                 if(t == '*' || t == '/' || t == '(')
    249                     tag = '<';
    250                 else
    251                     tag = '>';
    252                 break;
    253             case '*':
    254                 if(t == '(')
    255                     tag = '<';
    256                 else
    257                     tag = '>';
    258                 break;
    259             case '/':
    260                 if(t == '(')
    261                     tag = '<';
    262                 else
    263                     tag = '>';
    264                 break;
    265             case '(':
    266                 if(t == ')')
    267                     tag = '=';
    268                 else if(t == '#')
    269                     break;
    270                 else
    271                     tag = '<';
    272                 break;
    273             case ')':
    274                 if(t == '(')
    275                     break;
    276                 else
    277                     tag = '>';
    278                 break;
    279             case '#':
    280 
    281                 if(t == ')')
    282                     break;
    283                 else if(t == '#')
    284                     tag = '=';
    285                 else
    286                     tag = '<';
    287                 break;
    288         }
    289      
    290         return tag;
    291     }
    292 }

    程序结果截图:

    项目计划日志:

    时间记录日志:

    缺陷记录日志:

  • 相关阅读:
    项目实战:Qt+Android模拟操作器(模拟操作app,打开,点击,输入,获取验证码等等)
    项目实战:流水线图像显示控件(列刷新、1ms一次、缩放、拽拖、拽拖预览、性能优化、支持OpenGL GPU加速)
    OpenCV开发笔记(七十三):红胖子8分钟带你使用opencv+dnn+yolov3识别物体
    Oracle数据库由dataguard备库引起的log file sync等待
    使用udev高效、动态的管理Linux设备文件
    Linux配置和管理设备映射多路径multipath
    ELK6环境搭建
    存储系列1-openfiler开源存储管理平台实践
    redhat / centos开启关闭防火墙
    教你如何使用github+jsDelivr搭建免费图床
  • 原文地址:https://www.cnblogs.com/maosonglin/p/6532653.html
Copyright © 2011-2022 走看看