自动生成四则运算,及逆波兰算法求结果

目录

完成人员学号
黄俊宗3121005261

1.作业的基本信息

作业属于课程软件工程四班
作业的要求结对编程:小学四则运算
作业的目标实现一个自动生成小学四则运算题目的程序

2.作业地址

3121005261 gitcode地址

3.PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3060
Estimate估计这个任务需要多少时间120120
Development开发9090
Analysis需求分析 (包括学习新技术)90150
Design Spec生成设计文档6070
Coding Standard设计复审4045
Design代码规范 (为目前的开发制定合适的规范)2020
Design Review具体设计5050
Coding具体编码250330
Code Review代码复审4060
Test测试(自我测试,修改代码,提交修改)4040
Reporting报告120120
Test Repor测试报告6060
Size Measurement计算工作量3030
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划3060
Total合计12501440

4.效能分析

4.1 JProfiler分析

在这里插入图片描述

5.类与函数说明

5.1 关键算法逆波兰算法的流程图与代码实现

方法
Main(主函数调试)main()
Creat(随机数生成式子)single
create
file (文件处理)file_inArry
file_inString
file_out()
Reverse(逆波兰算法求答案)cal (逆波兰算法:中缀算式分栈变后缀,最后靠优先级计算直到变为一个栈顶元素)
Transform(小数转换真分式)gcd(求最大公约数)
transform(转换为真分式)

5.2关键算法逆波兰算法的流程图与代码实现

逆波兰(后缀)算法简介与流程图:

引用:逆波兰算法实现
在这里插入图片描述
在这里插入图片描述

6.代码说明

package calculation;


public class Create {
		
	//m:范围  n:题目数  fuao:+-*/   strArryay:式子数组
		String[] fuHao;
		int m;
		int n;
		String[] strArray;
		
	


		public Create(String[] fuHao, int m, int n, String[] strArray) {
			super();
			this.fuHao = fuHao;
			this.m = m;
			this.n = n;
			this.strArray = strArray;
		}
		
		//单式子生成
		public String single(int m,String[] fuHao)
		{
			String str;
            int first_number;
            int second_number;
			
            //随机生成符号
            int order = (int)(Math.random()*5);
            //生成两个数值
            first_number = (int)(Math.random()*m+1);
            second_number = (int)(Math.random()*m+1);
            
            //拼接四则运算式子
            //随机生成括号
            if(Math.random()*3>1&&(fuHao[order]==" + "||fuHao[order]==" - ")){
            	//添加括号
            	str ="(" + first_number + fuHao[order] + second_number + ")";
            }
            else {
            	str = first_number + fuHao[order] + second_number;
            }
            
			return str;
			
		}

		//利用随机数random生成n个式子,且结果不为负数
        public void create(int m, int n, String[] fuHao, String[] strArray) {
            String str = "";
            int i=0;
            
            //循环创造式子,终止条件:i==10
            outer:
            while(true) {
                str = "";
                int first_number;
                int second_number;
                
                int lastNumber;
                //最后一个数字的值 生成一个<max的随机数
                lastNumber = (int)(Math.random()*m+1);
                //循环两次,一单式子+一符号的形式
                for(int j = 0; j < 2; j++) {
               	
                	int order = (int)(Math.random()*5);
                	str = str + single(m, fuHao) + fuHao[order];
                }
                //最后拼接最好一个数字,完成2+2+1的四则运算形式
                str = str + lastNumber + " = ";
                
                // 如过出现负数结果则跳过
                if(Reverse.cal(str).charAt(0)=='-')
                {
                	continue outer;
                }
                //将式子存储在strArray数组中
                strArray[i] = str;
                System.out.println("第"+(i+1)+"题:"+str);
                if(i==9)
                {
                	break outer;
                }
                i++;
            }
//            System.out.println("\n");
        }
        
        public static void main(String[] args) {
        	
    		String[] fuhao = {"+","-","*","/","÷"} ;
    		int n=10;
    		int m=50;
    		String[] strArry = new String[n];
    		Create creat = new Create(fuhao, m, n, strArry);
    		
    		creat.create(m, n, fuhao, strArry);
    		
        	


		}
        
    }

package calculation;

import java.util.List;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Stack;
//使用逆波兰式
public class Reverse {
        public static String cal(String str) {
            //对表达式进行预处理,并简单验证是否是正确的表达式
            //存放处理后的表达式
            List<String> list = new ArrayList<>();
            //将空格与等号删去(replace)
            str.replace(" ", "");
            str.replace(" = ", "");
            char[] arr = str.toCharArray();
            //存放数字临时变量
            StringBuffer tmpStr = new StringBuffer();
            for (char c : arr) {
                //如果是数字或小数点,添加到临时变量中
                if (c>='0' && c<='9') {
                    tmpStr.append(c);
                }else if(c=='.') {
                    tmpStr.append(c);
                }
                //如果是加减乘除或者括号,将数字临时变量和运算符依次放入List中
                else if (c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')'||c=='÷') {
                    if (tmpStr.length() > 0) {
                        list.add(tmpStr.toString());
                        tmpStr.setLength(0);
                    }
                    list.add(c + "");
                }
                else if (c==' ') {
                    continue;
                }
            }
            if (tmpStr.length() > 0) {
                list.add(tmpStr.toString());
            }
            //初始化后缀表达式
            List<String> strList = new ArrayList<>();
            //运算过程中,使用了两次栈结构,
            //第一次是将中缀表达式转换成后缀表达式,第二次是计算后缀表达式的值
            Stack<String> stack = new Stack<>();
            //声明临时变量,存放栈元素
            String tmp;
            //将中缀表达式转换成后缀表达式(强调优先级)
            for (String s : list) {
                //如果是左括号直接入栈
                if (s.equals("(")) {
                    stack.push(s);
                }
                //如果是右括号,执行出栈操作,依次添加到后缀表达式中,直到出栈元素为左括号,左括号和右括号都不添加到后缀表达式中
                else if (s.equals(")")) {
                    while (!(tmp = stack.pop()).equals("(")) {
                        strList.add(tmp);
                    }
                }
                //如果是加减乘除,弹出所遇优先级大于或等于该运算符的栈顶元素(栈中肯定没有右括号,认为左括号的优先级最低),然后将该运算符入栈
                else if (s.equals("*") || s.equals("/")||s.equals("÷")) {
                    while(!stack.isEmpty()) {
                        //取出栈顶元素
                        tmp = stack.peek();//取出但不移除
                        if (tmp.equals("*") || tmp.equals("/")||tmp.equals("÷")) {
                            stack.pop();
                            strList.add(tmp);
                        }
                        else {
                            break;
                        }
                    }
                    stack.push(s);
                }
                else if (s.equals("+") || s.equals("-")) {
                    while(!stack.isEmpty()) {
                        //取出栈顶元素
                        tmp = stack.peek();
                        if (!tmp.equals("(")) {
                            stack.pop();
                            strList.add(tmp);
                        }
                        else {
                            break;
                        }
                    }
                    stack.push(s);
                }
                //如果是数字,直接添加到后缀表达式中
                else {
                    strList.add(s);
                }
            }
            //最后依次出栈,放入后缀表达式中
            while (!stack.isEmpty()) {
                strList.add(stack.pop());
            }
            //计算后缀表达式的值
            Stack<BigDecimal> newStack = new Stack<>();
            for (String s : strList) {
                //若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符的左边
                //运算后的结果再进栈,直到后缀表达式遍历完毕
                if (s.equals("*") || s.equals("/") || s.equals("+") || s.equals("-")||s.equals("÷")) {
                    BigDecimal b1 = newStack.pop();
                    BigDecimal b2 = newStack.pop();
                    switch (s) {
                        case "+":
                            newStack.push(b2.add(b1));
                            break;
                        case "-":
                            newStack.push(b2.subtract(b1));
                            break;
                        case "*":
                            newStack.push(b2.multiply(b1));
                            break;
                        //除法保留六位小数    
                        case "/":
                            newStack.push(b2.divide(b1, 4, BigDecimal.ROUND_HALF_UP));
                            break;
                        case "÷":
                            newStack.push(b2.divide(b1, 4, BigDecimal.ROUND_HALF_UP));
                            break;
                    }
                }
                //如果是数字,入栈
                else {
                    newStack.push(new BigDecimal(s));
                }
            }
            //栈中仅有一个元素,返回计算结果
            return newStack.peek().toString();
        }
    }


package calculation;


public class Transform {
	
	String result;
	
	public Transform(String s) {
		super();
		this.result=transform(s);
		// TODO Auto-generated constructor stub
	}

	//求公约数
    public static int gcd(int a,int b){
    	//利用gcd函数求得a与b最大公约数
        return b==0 ? a:gcd(b,a%b) ;
    }
    
    //收到一个小于1的小数,转为真分数
    public static String transform(String s)
    {
        //输入的小数
        String result="";
        int decimal;
        int a, b,c;
        int g;
//        number = in.next();

        //定义长度为2的数组,分别存放整数位和小数位。
        String[] array = new String[2];
        //分割字符串
        array = s.split("\\.");
        //整数部分
        a = Integer.parseInt(array[0]);
        //小数部分
        decimal = Integer.parseInt(array[1]);
        //核心部分:小数变分数
        int length = array[1].length();
        b = decimal;
        c = (int)Math.pow(10, length);
        g  = gcd(b,c);

        result =a+" ' "+b/g+"|"+c/g;
		return result;
		
    }


}

package calculation;

import java.io.IOException;
import java.util.function.DoubleConsumer;

public class Main {
	

	
	public static void main(String[] args) throws IOException {
		String[] fuhao = {" + "," - "," * "," / "," ÷ "} ;
		int n=10; //式子个数
		int m=50; //单数范围
		int score=0;//分数
		//用来存储式子的数组
		String[] str1 = new String[n];
		//用来存储答案的数组,多出一个用来存分数
		String[] str2 = new String[n+1];
		
		Create creat = new Create(fuhao, m, n, str1);
		creat.create(m, n, fuhao, str1);
		
		Reverse answer = new Reverse();
		
		//求答案,存到数组(转换答案:分数形式)
		int i=0;
		for(String s : str1)
		{
			str2[i]=answer.cal(s);
			//当出现小数时转为真分数
			if(str2[i].indexOf(".")!=-1)
			{
				str2[i]=Transform.transform(str2[i]);
			}
			i++;
		}

		
		file qf = new file("D:\\eclipse-workspace\\calculation\\txt_file\\question.txt");
		file af = new file("D:\\eclipse-workspace\\calculation\\txt_file\\answer.txt");
		file you = new file("D:\\eclipse-workspace\\calculation\\txt_file\\you.txt");
		
		//对答案
		String[] str3 =new String[n]; 
		str3=you.content.split("\n");
		for(int j=0;i<n;i++)
		{
			if(str2[j]==str3[j])
			{
				score++;
			}
		}
		//存分数
		str2[n]=String.valueOf(score)+"分";
		

		//将题目,答案,输入文件
		qf.file_inArry(str1);
		af.file_inArry(str2);

	}
}

7. 测试运行

运算题展示

在这里插入图片描述

输入展示

在这里插入图片描述

答案展示

在这里插入图片描述

项目小结

在这个结对项目中,我完成了一个基于Java的自动生成小学四则运算题目的命令行程序。通过这个项目,我学习到了很多新的技能和知识,也经历了许多成功和失败的时刻。
在项目完成之前,我首先遇到了一些技术难题,例如如何查重题目并去重、如何处理一些特殊情况等等。但是我通过不断学习,最终克服了这些问题,并成功实现了项目的目标。同时,在项目完成后,我也回顾了整个项目的过程,并总结了一些得失和教训。
首先,我认为这个项目的最大成功在于我的合作和沟通。在整个项目过程中,我保持了密切的联系,时刻互相了解对方的工作进度和遇到的问题,及时进行了交流和协作,从而确保了项目的顺利完成。其次,我也注意到了一些需要改进的地方,例如项目计划和时间管理方面还有待提高,代码质量方面还有需要改进的地方等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值