个人项目实战——用Java实现四则运算功能

我们老师最近布置了一项作业,让每个人用Java语言实现整数或是分数的四则运算功能。

具体需求如下:

1、程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。

2、每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3÷5+2=2.6,2-5+10=7等算式。

3、练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致。

4、支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号数必须大于2对,且不得超过运算符的个数。

5、支持真分数的出题与运算(只需要涵盖加减法即可),例如:1/6 + 1/8 + 2/3= 23/24。注意在实现本功能时,需支持运算时分数的自动化简,比如 1/2+1/6=2/3,而非4/6,且计算过程中与结果都须为真分数

我认为,整个项目的难点就在于将中缀表达式转化为后缀表达式,并将其计算出来。在这里我运用了逆波兰表达式和调度场算法。

下面是我的部分代码

public int algorithm(String s) {
        //放数字
        Stack<Integer> stack1 = new Stack<>();
        //放操作符
        Stack<String> stack2 = new Stack<>();
        //存放运算符优先级
        HashMap<String, Integer> hashmap = new HashMap<>();
        hashmap.put("(", 0);
        hashmap.put("+", 1);
        hashmap.put("-", 1);
        hashmap.put("*", 2);
        hashmap.put("÷", 2);

        for (int i = 0; i < s.length();) {
            //设置可变长的字符串
            StringBuffer digit = new StringBuffer();
            //将式子字符串切割为c字符
            char c = s.charAt(i);
            //判断字符是否为10进制数字,将一个数加入digit
            while (Character.isDigit(c)) {
                digit.append(c);
                i++;
                c = s.charAt(i);
            }
            //当前digit里面已经无数字,即当前处理符号
            if (digit.length() == 0){
                switch (c) {
                    case '(': {
                        stack2.push(String.valueOf(c));
                        break;
                    }
                    //遇到右括号了计算,因为(的优先级最高
                    case ')': {
                        String stmp = stack2.pop();
                        while (!stack2.isEmpty() && !stmp.equals("(")) {
                            int a = stack1.pop();
                            int b = stack1.pop();
                            int sresulat = calculate(b, a, stmp);
                            if(sresulat<0)
                                return  -1;
                            stack1.push(sresulat);
                            //符号指向下一个计算符号
                            stmp = stack2.pop();
                        }
                        break;
                    }
                    case '=': {
                        String stmp;
                        while (!stack2.isEmpty()) {
                            stmp = stack2.pop();
                            int a = stack1.pop();
                            int b = stack1.pop();
                            int sresulat = calculate(b, a, stmp);
                            if(sresulat<0)
                                return  -1;
                            stack1.push(sresulat);
                        }
                        break;
                    }

                    default: {
                        String stmp;
                        while (!stack2.isEmpty()) {
                            stmp = stack2.pop();
                            //比较优先级
                            if (hashmap.get(stmp) >= hashmap.get(String.valueOf(c))) {
                                int a = stack1.pop();
                                int b = stack1.pop();
                                int sresulat =calculate (b, a, stmp);
                                if(sresulat<0)
                                    return  -1;
                                stack1.push(sresulat);
                            }
                            else {
                                stack2.push(stmp);
                                break;
                            }

                        }
                        //将符号压入符号栈
                        stack2.push(String.valueOf(c));
                        break;
                    }
                }
            }
            else {
                //处理数字
                stack1.push(Integer.valueOf(digit.toString()));
                continue;
            }
            i++;
        }
        //返回栈底得到答案
        return stack1.peek();
    }
private int calculate(int a, int b, String stmp) { //计算a stmp b的值
        int res = 0;
        char s = stmp.charAt(0);
        switch (s) {
            case '+': {
                res = a + b;
                break;
            }
            case '-': {
                //判断是否产生负数
                res = a - b;
                break;
            }
            case '*': {
                res = a * b;
                break;
            }
            case '÷': {
                if(b==0)
                    return -1;
                //判断是否产生小数
                else if(a%b!=0)
                    return -2;
                else
                    res = a / b;
                break;
            }
        }
        return res;
    }

这是算法部分

public class Create {
    public String createProblem(){  //产生整数式子
        Random r = new Random();
        String[] opertor = {"+","-","*","÷"};
        //操作符的个数
        int operatorNum = 3+r.nextInt(3);
        //新建数组来保存操作数
        int[] number = new int[operatorNum+1];
        //操作符的下标
        int[] arr = index(operatorNum);
        String s = new String();

        for(int j=0;j<operatorNum+1;j++){
            number[j] = r.nextInt(101);
        }



        //如果flag=0,则该式子加括号,如果flag=1,则该式子不加括号(自己设定)
        int flag = r.nextInt(2);

        switch (operatorNum){
            case 3:{
                if(flag == 0){
                    s = "(" + number[0] + opertor[arr[0]] + number[1] + ")" +opertor[arr[1]]+ "(" + number[2] + opertor[arr[2]] + number[3] + ")";
                }
                else{
                    s = number[0] + opertor[arr[0]] + number[1]+opertor[arr[1]]+number[2] + opertor[arr[2]] + number[3] ;
                }
                break;
            }
            case 4:{
                if(flag ==0){
                    s = "(" + "(" + number[0] + opertor[arr[0]] + number[1] + ")" + opertor[arr[1]] + number[2] + ")" + opertor[arr[2]] + "(" + number[3] + opertor[arr[3]] + number[4] + ")";
                }
                else{
                    s = number[0] + opertor[arr[0]] + number[1] +opertor[arr[1]] + number[2] + opertor[arr[2]] + number[3] + opertor[arr[3]] + number[4] ;
                }
                break;
            }
            case 5:{
                if(flag ==1){
                    s = "(" + "(" + number[0] + opertor[arr[0]]+number[1]+")" + opertor[arr[1]] + number[2] + ")" +opertor[arr[2]]+ "(" + "(" + number[3] + opertor[arr[3]] + number[4] + ")" + opertor[arr[4]] + number[5] + ")";
                }
                else{
                    s = number[0] + opertor[arr[0]]+number[1]+ opertor[arr[1]] + number[2] +opertor[arr[2]] + number[3] + opertor[arr[3]] + number[4] + opertor[arr[4]] + number[5] ;
                }
                break;
            }
        }


        s+="=";
        Calculator calculator = new Calculator();
        int answer = calculator.algorithm(s);

        //判断式子是否符合要求,凡是返回负数的就是不合格的
        if(answer>=0){
            s+=answer;
        }else {
            //递归
            return createProblem();
        }

        return s;

    }


    public int[] index(int n){ //产生操作符的下标数组
        Random random = new Random();
        int similar=0;
        int[] a = new int[n];
        for(int j=0;j<n;j++){
            a[j] = random.nextInt(4);
        }
        for(int j=1;j<n;j++){
            if(a[0]==a[j]) similar++;
        }
        //保证一个式子里至少有2个不同的操作符
        if(similar==n-1) return index(n);
        else {
            return a;
        }

    }

}

产生整数式子

public class ProperFraction { 
    public String createProblem(){
        Random r = new Random();
        String[] operator = {"+","-"};
        int operatorCount = 3+r.nextInt(3); 


        int[] index = index2(operatorCount); 

        int sumx = 1+r.nextInt(10); 
        int sumy = 1+r.nextInt(20);
        int g = maxG(sumx,sumy);
        sumx/=g;
        sumy/=g;

        int[] fenshu = huajian(sumx, sumy);
        sumx = fenshu[0];
        sumy = fenshu[1];
        //第一个数
        String s=sumx+"/"+sumy; 

        for(int i=0;i<operatorCount;i++){
            int numx = r.nextInt(10);
            int numy = 1+r.nextInt(20); 
            String currentOpreator = operator[index[i]];
            fenshu = huajian(numx, numy);
            numx = fenshu[0];
            numy = fenshu[1];
            if(currentOpreator.equals("+")) { 
                fenshu = huajian(sumx * numy + sumy * numx, sumy * numy);
                sumx = fenshu[0];
                sumy = fenshu[1];
            }
            else {   //减法
                while(sumx*numy-sumy*numx<0) 
                {
                    numx=r.nextInt(10);
                    numy=1+r.nextInt(20);
                    g=maxG(numx,numy);
                    numx/=g;
                    numy/=g;
                }
                sumx=sumx*numy-sumy*numx;
                sumy=sumy*numy;
            }
            s+=currentOpreator+numx+"/"+numy;
        }

        g = maxG(sumx,sumy);
        sumx/=g; 
        sumy/=g;

        if(sumx==0) s+="="+sumx;
        else if(sumx==1&&sumy==1) s+="="+sumx;
        else s+="="+sumx+"/"+sumy;

        return s;

    }

    public int maxG(int fenzi,int fenmu)//求最大公因数
    {
        while (fenmu != 0) {
            int r = fenzi % fenmu;
            fenzi = fenmu;
            fenmu = r;
        }
        return fenzi;
    }
    
    public int[] index2(int n) { 
        Random random = new Random();
        int similar = 0;
        int[] a = new int[n];
        for (int j = 0; j < n; j++) {
            a[j] = random.nextInt(2);
        }
        for (int j = 1; j < n; j++) {
            if (a[0] == a[j]) similar++;
        }
        if (similar == n - 1) return index2(n); 
        else {
            return a;
        }

    }
    public int[] huajian(int fenzi, int fenmu){
        Random r = new Random();
        while (fenzi >= fenmu) {
            fenzi = 1 + r.nextInt(10);
            fenmu = 1 + r.nextInt(20);
            int g = maxG(fenzi, fenmu);
            fenzi = fenzi / g;
            fenmu = fenmu / g;
        }
        int[] fenshu = new int[2];
        fenshu[0] = fenzi;
        fenshu[1] = fenmu;
        return fenshu;
    }
}

产生分数式子

这三块便是整个项目最核心的部分便是这三个部分。

接下来就是项目功能的展示

在命令行进行测试

得到result.txt文件

下面是我的PSP

PSP2.1

任务内容

计划共完成需要的时间(h)

实际完成需要的时间(h)

Planning

计划

2

3

·        Estimate

·   估计这个任务需要多少时间,并规划大致工作步骤

2

3

Development

开发

46.5

69.5

·        Analysis

·         需求分析 (包括学习新技术)

2

4

·        Design

·         具体设计

1

1

·        Coding

·         具体编码

38

46

·        Code Review

·         代码复审

0.5

0.5

·        Test

·         测试(自我测试,修改代码,提交修改)

5

18

Reporting

报告

0.8

1

·         Size Measurement

·         计算工作量

0.3

0.5

·         Postmortem & Process Improvement Plan

·         事后总结, 并提出过程改进计划

0.5

0.5

 

改进

       我在生成括号的地方偷了个小懒,没有用生成随机数的方式来让式子随机生成括号的位置,我想,在以后,这是可以再进行改进的地方

个人感悟:

       这次的项目让我感触颇多,同时也让我收获了许多。

       由于很久没有写过Java程序了,以至于我都忘记了idea里的环境怎么配,只得一点一点从头再来。在开始写这个作业的时候,我有点无从下手,于是就一个一个地把需求在纸上罗列了出来,就是这样

这才使我的思路逐渐清晰。在代码基本完成,开始测试的时候又出了很多的问题,有时我在命令行测试的时候会出现一些莫名其妙的错误,比如找不到主类,数组下标越界,甚至直接告诉我我的内存不够了,在解决这些问题的时候真的是心力交瘁,有的时候甚至想,算了算了,直接随便找一份交上去算了,但是后来还是休息之后,继续和这些bug作斗争!

虽说这次作业耗费了很多的精力,但是在这次的项目中,我收获了宝贵的经验以及技术的大幅进步,哈哈哈哈哈,程序员不就是这样嘛,在一次又一次的实战中不断进步,不断成长!
 

 

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值