• 四则运算四


    (结对伙伴:毛雯雯 20143066 编程和撰写博客的过程在一个笔记本上 所以该博客是以及程序是两个人合作的结果 )

    一:作业要求:

    1、 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2。

    2、生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。

    3、每道题目中出现的运算符个数不超过3个,括号不限。

    4、程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。

    5、把程序变成一个网页程序, 用户通过设定参数,就可以得到各种题目,并可实现在线答题并评判。

    二、设计思想:

    首先,解决括号的问题(创建一个有括号的式子);其次,将这个式子放入栈(上次在网上查找到的栈的代码)中实现计算结果的目的,以实现评分的目的;然后,对减号,除号,运算符个数,设定参数重复性,网页版的问题进行解决。

      具体解决:

        创建式子:将数字和运算符放入两个数组中,随机生成符号的个数,随机生成数的个数,使用DFS实现括号的插入,插入的位置随机。

        计算:将生成的式子放入栈中计算。

        减号:(实现有错,暂未实现)使用遍历,遍历到减号,减号左右的保证左大于右(问题详细:连续减号和后面为乘除的情况)

        除号:(实现有错,暂未实现)使用遍历,遍历到除号,除号左右保证真分数(问题详细:连续除法不能保证)

        运算符个数:创建式子的时候,控制运算符的个数即可。

        设定参数:主要设置了范围,在随机生成运算数的时候设定范围(传参)

        网页版:(尝试,未实现,仅做出界面)使用JSP,不太会JAVA到JSP语句的转换。

    三 源代码:

    import java.util.Arrays;
    import java.util.Scanner;
    import java.util.Stack;   //
    class CreateExp {
        private int a[];
        private char s[];
        private char sym[];
        private char brackets[];
        private int num[];
    
        public CreateExp() 
        {
            a = new int[100];
            s = new char[4];
            s[0] = '+';
            s[1] = '-';
            s[2] = '*';
            s[3] = '/';
            sym = new char[100];
            brackets = new char[100];
            num = new int[100];
        }
    
        public void dfs(int s, int e)// 使用dfs递归添加括号
        {
            if ((int) (Math.random() * 4) == 0) // 四分之一的概率,不进行任何操作
            {
                return;
            }
            if (e - s <= 1)// 只有一个元素或没有元素,不进行任何操作
            {
                return;
            }
            int s1 = (int) (Math.random() * (e - s - 1)) + s;// 随机生成插入括号的位置
            int e1 = (int) (Math.random() * (e - s1)) + s1;
            while (s1 < s || e1 > e || s1 >= e1 || (s1 == s && e1 == e))// 避免无用括号
            {
                s1 = (int) (Math.random() * (e - s - 1)) + s;
                e1 = (int) (Math.random() * (e - s1)) + s1;
            }
            if (brackets[s1] == ')' || brackets[e1] == '(')
            {
                return;
            }
            brackets[s1] = '(';
            brackets[e1] = ')';
            num[s1]++;
            num[e1]++;
            dfs(s, s1 - 1);// 插入括号的左边几个元素
            dfs(e1 + 1, e);// 括号之间的几个元素
            dfs(s1, e1);// 括号右边的几个元素
        }
    
        String Create(int max,int min) 
        {
            int n;
            String ans;
            ans = "";
            n = (int) (Math.random() * (3)) + 2;
            ;
            Arrays.fill(brackets, '.');
            Arrays.fill(num, 0);
            
            for (int i = 1; i <= n; i++) 
            {
                a[i] = (int) ((max-min+1)*Math.random() ) + min;
                sym[i] = s[(int) (Math.random() * (4))];
            }
            /*for(int i = 1; i <= n; i++)
            {   
                int middle;
                if(sym[i]=='-'&&a[i]<a[i+1])
                {
                    middle=a[i];
                    a[i]=a[i+1];
                    a[i+1]=middle;
                }
                    
            }*/
            dfs(1, n);
            while ((brackets[1] == '(') && (num[1]-- != 0)) 
            {
                ans += '(';
            }
            ans += a[1] + "";
            for (int i = 2; i <= n; i++) 
            {
                ans += sym[i];
                while (brackets[i] == '(' && num[i]-- != 0) 
                {
                    ans += '(';
                }
                ans += a[i] + "";
                while (brackets[i] == ')' && num[i]-- != 0) 
                {
                    ans += ')';
                }
            }
            return ans;
        }
    }
    public class CalculatorUtil //计算  
    { 
        private Stack<Character> priStack = new Stack<Character>();// 操作符栈    
        private Stack<Integer> numStack = new Stack<Integer>();// 操作数栈    
       
        public double caculate(String str) 
        {  //计算  
            String temp;//临时存放读取的字符
            StringBuffer tempNum = new StringBuffer(); //  用来临时存放数字字符串(当为多位数时) 
            StringBuffer string = new StringBuffer().append(str);  //用来保存,提高效率 
           
            while (string.length() != 0) //当没有余留才计算完成
            {    
                temp = string.substring(0, 1);    
                string.delete(0, 1);  
               // 判断temp,当temp为操作符时 
                if (!isNum(temp)) 
                {   
                    // 此时的tempNum内即为需要操作的数,取出数,压栈,并且清空tempNum   
                    if (!"".equals(tempNum.toString())) 
                    { 
                        // 当表达式的第一个符号为括号   
                        int num=Integer.parseInt(tempNum.toString());
                        numStack.push(num);
                        tempNum.delete(0, tempNum.length());    
                    } 
                 // 用当前取得的运算符与栈顶运算符比较优先级:若高于,则因为会先运算,放入栈顶;若等于,因为出现在后面,所以会后计算,所以栈顶元素出栈,取出操作数运算;   
                    // 若小于,则同理,取出栈顶元素运算,将结果入操作数栈。   
                
                    // 判断当前运算符与栈顶元素优先级,取出元素,进行计算(因为优先级可能小于栈顶元素,还小于第二个元素等等,需要用循环判断)   
                    while (!compare(temp.charAt(0)) && (!priStack.empty())) { 
                        int a =  numStack.pop();  //第二个和第一个运算数  
                        int b =  numStack.pop();   
                        char ope = priStack.pop();    
                        int result = 0;  //运算结果 
                        switch (ope) 
                        {    
                        // 将操作结果放入操作数栈 
                            case '+':    
                                result = b + a;    
                                numStack.push(result);    
                                break;    
                            case '-':    
                                result = b - a;    
                                numStack.push(result);    
                                break;    
                            case '*':    
                                result = b * a;    
                                numStack.push(result);    
                                break;    
                            case '/':    
                                result = b / a;    
                                numStack.push(result);    
                                break;    
                        }    
        
                    }
                 // 判断当前运算符与栈顶元素优先级, 如果高,或者低于平,计算完后,将当前操作符号,放入操作符栈 
                    if (temp.charAt(0) != '#') 
                    {    
                        priStack.push(new Character(temp.charAt(0)));    
                     // 当栈顶为'(',而当前元素为')'时,则是括号内以算完,去掉括号
                        if (temp.charAt(0) == ')')
                        {
                            priStack.pop();    
                            priStack.pop();    
                        }    
                    }    
                } 
                else    // 当为非操作符时(数字)
                    // 将读到的这一位数接到以读出的数后(当不是个位数的时候)
                    tempNum = tempNum.append(temp);  
            }    
            return numStack.pop();    
        }    
        //判断传入的字符是不是0-9的数字  
        private boolean isNum(String temp)
        {    
            return temp.matches("[0-9]");    
        }    
        
        //比较当前操作符与栈顶元素操作符优先级,如果比栈顶元素优先级高,则返回true,否则返回false  
         
        // 需要进行比较的字符  
        //比较结果 true代表比栈顶元素优先级高,false代表比栈顶元素优先级低  
        
        private boolean compare(char str) 
        {    
            // 当为空时,显然 当前优先级最低,返回高 
            if (priStack.empty()) 
            {    
                return true;    
            }    
            // 如果栈顶为'('显然,优先级最低,')'不可能为栈顶。
            char last = (char) priStack.lastElement();    
            if (last == '(') 
            {    
                return true;    
            }    
            switch (str) 
            {    
                case '#':    
                    return false;  
                case '(':      
                    return true;    
                case ')':    
                    return false;    
                case '*': 
                {    
                    if (last == '+' || last == '-')    
                        return true;    
                    else    
                        return false;    
                }    
                case '/': 
                {    
                    if (last == '+' || last == '-')    
                        return true;    
                    else    
                        return false;    
                }     
                case '+':    
                    return false;    
                case '-':    
                    return false;    
                }    
                return true;    
            }    
        
        public static void main(String args[]) 
        {    
            /*CalculatorUtil operate = new CalculatorUtil();    
            double t = operate.caculate("(3+4*(4*10-15/9)#");      
            System.out.println(t);  */
            
            Scanner in=new Scanner(System.in);      
            System.out.println("请输入要输出的算式的个数:");
            int n=in.nextInt();
            
            System.out.println("请输入数据范围  请先输入上界 再输入下界");
            Scanner in1=new Scanner(System.in);
            int max1=in1.nextInt();
            int min1=in1.nextInt();
            
            int result;
            int count=0;
            
            for(int x=0;x<n;x++)
            {   
                CreateExp exp = new CreateExp()  ;
                CalculatorUtil cal =new CalculatorUtil() ;
                String expString = exp.Create(max1,min1);
                double ans = cal.caculate(expString+"#");
                System.out.println(expString+"=");
                System.out.println("请输入结果:");
                 result=in.nextInt();
                if(result==ans)
                {
                    System.out.println("结果正确!");
                    count++;
                }
                if(result!=ans)
                {
                    System.out.println("结果错误 答案为: "+ans);
                }
            }
            System.out.println("共做对"+count+"个,"+"做错"+(n-count)+"个。");
        }    
        
    }

    四、运行截图:

    五。反思:本以为符号的个数少,可以直接用枚举的方法,但是,无法进行计算,进行评判,还是回来继续用了栈。另外,减号和除号的不太会处理,总是有错误!

    我们一起研究了栈,想把大神的程序看懂移植过来,但是失败了。我们也打算用枚举,结果输出一直有错,最后不得不放弃这个偷懒的做法。

  • 相关阅读:
    C# 控制台应用程序输出颜色字体[更正版]
    ORM for Net主流框架汇总与效率测试
    php 去掉字符串的最后一个字符
    bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包
    bzoj [Noi2008] 1061 志愿者招募 单纯形
    bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp
    扩展欧几里得(ex_gcd),中国剩余定理(CRT)讲解 有代码
    BZOJ 2103/3302/2447 消防站 树的重心【DFS】【TreeDP】
    hihocoder 1449 后缀自动机三·重复旋律6
    hihocoder 后缀自动机二·重复旋律5
  • 原文地址:https://www.cnblogs.com/3066405538a/p/5372026.html
Copyright © 2020-2023  润新知