码迷,mamicode.com
首页 > 其他好文 > 详细

软件工程个人作业02

时间:2017-03-10 19:09:14      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:scan   eval   string   异常   算法   技术   bool   method   express   

程序设计思想:

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

         将算术式封装成一个类,用字符串来存放一个算式。在这个类中,主要的问题还是如何构造算式。运算符、操作数和操作数的个数都可以用随机数来生成。但是,有三项难题需要解决:控制乘除有没有余数、加减有没有复数和控制有没有括号。要控制结果首先需要求出结果。现在已经不再是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==‘\t‘||ch==‘\n‘)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 }

 

程序结果截图:

技术分享

 

 

技术分享

 

 

技术分享

 

项目计划日志:

技术分享

时间记录日志:

技术分享

 

缺陷记录日志:

技术分享

软件工程个人作业02

标签:scan   eval   string   异常   算法   技术   bool   method   express   

原文地址:http://www.cnblogs.com/maosonglin/p/6532653.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!