软件工程概论个人作业02
这周的四则运算项目要求增多:主要有以下几个方面

编程思路:
1.随着老板所列出的要求的增多,必须将控制参数的实现都封装在函数中,以便程序的理解和规范性。
2.根据出题的难度,随机数确定运算式包含的参数个数,随机数确定符号,参数个数比运算符号多一个,生成题目;
3.将题目传给栈,由栈计算结果,并返回结果;
4.用随机数确定加减的运算数,根据随机数确定加减法还是乘除法(2个运算符还是4个运算符),比对输入的结果,若有余数则输入余数(以字符串形式保存);
5.设计分数类,其中包括分数的加减乘除以及输出形式的函数。(真分数,先产生分母,之后产生0-分母数值的分子);
6.括号的实现,设运算式长度为n,则可建立一个长度为n的数组名为KuoHao[],记录每个元素周围的括号情况,0为无括号,正数为左括号,负数为右括号。则可以产生的括号的长度(即括号包围的运算数的个数)为2 ~ (n-1),利用for循环控制括号的长度,循环变量 i 为2 ~ (n - 1),循环体是另一个循环,循环变量 j 为0 ~ (n - i + 1) (即可以加左括号的运算数的位置),如果括号添加正确,其相对应值相加为0,否则添加不正确。
代码:
package hh;
import java.util.Random;
import java.util.Scanner;
import java.util.Stack;
//分数类
class fraction {
public int fenMu,fenZi;
public int getFenMu() {
return fenMu;
}
public void setFenMu(int fenMu) {
this.fenMu = fenMu;
}
public int getFenZi() {
return fenZi;
}
public void setFenZi(int fenZi) {
this.fenZi = fenZi;
}
public fraction(int fenMu, int fenZi) {
this.fenMu = fenMu;
this.fenZi = fenZi;
yueFen();
}
public fraction(){}
//找出两数的最大公约数
public int MaxCommon(int a,int b){
//保证第一个参数大于第二个参数
if(a<b)
{
int temp;
temp=a;
a=b;
b=temp;
}
while(a%b!=0) //在余数不为零时循环
{
int temp=a%b;
a=b;
b=temp;
}
return b; //返回最大公约数
}
//找出两数的最小公倍数
public int MinCommon(int a,int b){
return a*b/MaxCommon(a,b);
}
//约分化简
public void yueFen(){
int y = 1;
for(int i = fenZi;i > 1;i--){
if(fenZi % i == 0 && fenMu % i == 0){
y = i;
break;
}
}
fenZi /= y;
fenMu /= y;
}
//计算(加)
public fraction add(fraction b){
fraction c = null;
int newFenZi = this.fenZi * b.getFenMu() + this.fenMu * b.getFenMu();
int newFenMu = this.fenMu * b.getFenMu();
c = new fraction(newFenMu,newFenZi);
return c;
}
//计算(减)
public fraction subtract(fraction b){
fraction c = null;
int newFenZi = this.fenZi * b.getFenMu() - this.fenMu * b.getFenZi();
int newFenMu = this.fenMu * b.getFenMu();
c = new fraction(newFenMu,newFenZi);
return c;
}
//计算(乘)
public fraction multiply(fraction b){
fraction c = null;
int newFenZi = this.fenZi * b.getFenZi();
int newFenMu = this.fenMu * b.getFenMu();
c = new fraction(newFenMu,newFenZi);
return c;
}
//计算(除)
public fraction divide(fraction b){
fraction c = null;
int newFenZi = this.fenZi * b.getFenMu();
int newFenMu = this.fenMu * b.getFenZi();
c = new fraction(newFenMu,newFenZi);
return c;
}
//输出分数形式
public String toString(){
if(fenZi != 0){
return fenZi + "/" + fenMu;
}
return "0";
}
}
public class kk {
public static String[] Answer=new String[100];
//生成整数计算式添加限制条件,type为运算式类型 0代表整数式,1代表真分数式
public static String[] createYunSuanShi(int hasChengChu,int hasKuoHao,int hasFuShu,int hasYuShu,int minNum,int maxNum,int n,int type) {
int i = 0;
int z = 0;
String yunSuanShiTemp;
String[] yunSuanShiArray = new String[n];
int operatorScope = 2 + 2 * hasChengChu;//运算符范围,2或4,2代表只有加减,4代表有加减乘除
int length;
String[] operatorArray = {"+","-","*","/"};
String[] operatorNum = null;//存储运算数
int num_index;//运算数下标
String[] operatorSymbol = null;//存储运算符
int symbol_index;//运算符下标
int[] brackets = null;//存储括号个数
while(i < n) {
length = Integer.parseInt(getOperatorNumber(0, 0,9)) + 2;//计算式运算数长度
operatorNum = new String[length];
operatorSymbol = new String[length - 1];
num_index = 0;
symbol_index = 0;
operatorNum[num_index++] = getOperatorNumber(type,minNum, maxNum);//随机生成操作数
for(int j = 0;j < length - 1;j++){
operatorSymbol[symbol_index++] = operatorArray[Integer.parseInt(getOperatorNumber(0,0,operatorScope-1))];//随机生成操作符
operatorNum[num_index++] = getOperatorNumber(type, minNum,maxNum);//随机生成操作数
}
if(hasKuoHao == 1){
brackets = randomAddBracket(length);//生成括号数组
}
//构造运算式
yunSuanShiTemp = "";
for(int j = 0;j < length;j++){
//添加左括号
if(hasKuoHao == 1){
for(int k = 0;k < brackets[j];k++){
yunSuanShiTemp += "(";
}
}
yunSuanShiTemp += " " + operatorNum[j] + " ";//加上运算数
//添加右括号
if(hasKuoHao == 1){
for(int k = 0;k > brackets[j];k--){
yunSuanShiTemp += ")";
}
}
//如果不是最后一个运算数则要加上运算符
if(j != length - 1){
yunSuanShiTemp += operatorSymbol[j];
}
}
//计算结果
String answer = expressCalculate(yunSuanShiTemp, hasFuShu, hasYuShu, type, length - 1);
if((answer.equals("ERROR"))){
continue;
}
yunSuanShiTemp += "=" /*+ answer*/;
Answer[z]=answer;
z++;
//检验重复
boolean chongFu = false;
for(int j = 0;j < i;j++){
if((yunSuanShiArray[j].equals(yunSuanShiTemp))){
chongFu = true;
break;
}
}
if(chongFu == false){
yunSuanShiArray[i++] = yunSuanShiTemp;
}
}
return yunSuanShiArray;
}
//表达式计算,参数为字符串类型的运算式
public static String expressCalculate(String express,int hasFuShu,int hasYuShu,int type,int symbolNum){
Stack<String> num = new Stack<String>();
Stack<String> symbolS = new Stack<String>();
symbolS.push("#");
express += "#";
char ch;
int i = 0;
int s = 0;
ch = express.charAt(i);
while(s < symbolNum){
if(ch == ' '){//读到空格,说明开始读运算数
String readNumStr = "";
while(true){
ch = express.charAt(++i);
if(ch == ' '){
break;
}
readNumStr += ch;
}
if((i + 1) < express.length()){
ch = express.charAt(++i);
}
num.push(readNumStr);
}else{//读到的是运算符
char compare = priorityCompare(symbolS.peek(),ch + "");
if(compare == '='){//如果是右括号
symbolS.pop();
ch = express.charAt(++i);
}else if(compare == '>'){//ch的优先级小于栈顶的优先级 比栈顶的优先级高就不算,入栈,低就弹栈运算
//弹出两个运算数,弹出一个运算符
String bStr = num.pop();
String aStr = num.pop();
String symbolT = symbolS.pop();
String c = yunSuan(aStr,bStr,symbolT,hasFuShu,hasYuShu,type);
if(c.equals("ERROR")){
return "ERROR";
}else if(c.indexOf("余") >= 0 && s != symbolNum - 1){//有余数
return "ERROR";
}else{
num.push(c);
}
s++;
}else{
symbolS.push(ch + "");
if((i + 1) < express.length()){
ch = express.charAt(++i);
}
}
}
}
return num.pop();
}
public static String yunSuan(String aStr,String bStr,String symbol,int hasFuShu,int hasYuShu,int type){
if(type == 0){//整数
int a = Integer.parseInt(aStr);
int b = Integer.parseInt(bStr);
if(symbol.equals("+")){
return "" + (a + b);
}else if(symbol.equals("-")){
if(a - b < 0 && hasFuShu == 0){
return "ERROR";
}else{
return "" + (a - b);
}
}else if(symbol.equals("*")){
return "" + (a * b);
}else{
if(b == 0){
return "ERROR";
}
if(a % b == 0){
return "" + (a / b);
}else{
if(hasYuShu == 1){
return (a / b) + "余" + (a % b);
}else{
return "ERROR";
}
}
}
}else{//分数
String[] af = aStr.split("/");
String[] bf = bStr.split("/");
if(af[0].equals("0") || bf[0].equals("0")){
return "ERROR";
}
fraction a = new fraction(Integer.parseInt(af[1]),Integer.parseInt(af[0]));
fraction b = new fraction(Integer.parseInt(bf[1]),Integer.parseInt(bf[0]));
if(symbol.equals("+")){
return a.add(b).toString();
}else if(symbol.equals("-")){
fraction c = a.subtract(b);
if(hasFuShu == 1 && c.getFenZi() < 0){
return "ERROR";
}
return c.toString();
}else if(symbol.equals("*")){
return a.multiply(b).toString();
}else{
return a.divide(b).toString();
}
}
}
//判断优先级
public static char priorityCompare(String a,String b){
char[][] priority = {
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=','>'},
{'>','>','>','>',' ','>','>'},
{'<','<','<','<','<',' ','='}
};
int a_index = index_symbol(a);
int b_index = index_symbol(b);
return priority[a_index][b_index];
}
public static int index_symbol(String a){
String p = "+-*/()#";
return p.indexOf(a);
}
//随机生成括号,参数为运算式的运算数的个数
public static int[] randomAddBracket(int length){
int[] brackets = new int[length];
for(int i = 0;i < brackets.length;i++) brackets[i] = 0;
Random rd = new Random();
for(int i = 2;i < length;i++){//添加的括号长度(括号包围的运算数的个数)
for(int j = 0;j < length - i + 1;j++){
int t = rd.nextInt(2);//随机生成0或1,0代表不加括号,1代表加括号
if(t == 1){
if(brackets[j] >= 0 && brackets[j + i - 1] <= 0){//要加的括号的第一个运算数周围没有右括号,且 最后一个运算数周围没有左括号
int counteract = 0;
for(int k = j;k < j + i;k++){//将要加的括号之间的所有运算数对应的brackets相加,
//如果和为0说明这个括号之间的括号是匹配的,不会出现括号交叉现象
counteract += brackets[k];
}
if(counteract == 0){
brackets[j]++;
brackets[j + i - 1]--;
}
}
}
}
}
return brackets;
}
//随机生成一个运算数( type==0代表生成整数,type==1代表生成真分数,maxNum代表数值范围 0-(maxNum-1) )
public static String getOperatorNumber(int type,int minNum,int maxNum){
Random rd = new Random();
int a;
while(true){
a = rd.nextInt(maxNum-minNum)+minNum;
if(type == 0){//随机生成一个整数
return "" + a;
}else{//随机生成一个真分数
if(a == 0){
continue;
}
int b = rd.nextInt(a-minNum)+minNum;
fraction c = new fraction(a,b);
return c.toString();
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
System.out.print("请输入所要生成题目的数目:");
int n = sc.nextInt();
System.out.print("请输入: 0、整数式 ; 1、分数式:");
int type = sc.nextInt();
System.out.print("是否有乘除法?(1有,0没有):");
int hasChengChu = sc.nextInt();
System.out.print("是否有括号?(1有,0没有):");
int hasKuoHao = sc.nextInt();
System.out.print("加减有无负数?(1有,0没有):");
int hasFuShu = sc.nextInt();
System.out.print("除法有无余数?(1有,0没有):");
int hasYuShu = sc.nextInt();
System.out.print("数值范围(最小数):");
int minNum = sc.nextInt();
System.out.print("数值范围(最大数):");
int maxNum = sc.nextInt();
String[] yunSuanShiArray = createYunSuanShi(hasChengChu, hasKuoHao, hasFuShu, hasYuShu,minNum, maxNum, n, type);
for(int i = 0;i < yunSuanShiArray.length;i++){
System.out.print(yunSuanShiArray[i]);
String result=sc.next();
if(result.equals(Answer[i])){
System.out.print(" 回答正确!");
}
else{
System.out.print(" 回答错误!"+"正确答案为:"+Answer[i]);
}
System.out.println();
}
sc.close();
}
}
结果截图:

编程总结:
1)程序虽然可以实现初步的需求出题,算题,并对结果进行判断,但还有很多地方需要改善,比如代码的重复,以及数值范围的规范性;
2)其中编程过程中也是汲取了一些其他同学的想法,希望以后自己可以独立思考,完成任务;
3)此实验中有关结果的诸多方面未考虑完全,比如正确率、或者是错题集等等,需要利用下一周的时间进行最后的修改、完善。
三、项目计划日志

四、时间记录日志

五、缺陷记录日志


浙公网安备 33010602011771号