20165316 结对编程第二周总结
结对编程第二周总结(整体总结)
由于上周并未完成整体代码,本周搭档与我加班加点进行本次作业的编写,并在4月21日(周六)完成了本次代码并实现了作业的大部分要求
UML图
我觉得这个程序的编写更类似于c语言的函数,体现类封装的部分只有真分数和真分数的运算。于是UML就在此不做赘述。
代码解析
分数的实现部分
对于分数的形式,如果分子分母有最大公因子,那么就进行约分的操作;如果分子分母互素,则分子分母与原分子分母保持不变;如果分子分母同时为负或者分母为负,则分子分母同时取相反数。这一部分同时完成了分子分母的设置方法。
代码实现如下:
public class Rational extends Object{
int numerator = 1 ; //分子
int denominator = 1; //分母
Rational(){}
Rational(int a,int b){
if(b!=1){
int c = f(Math.abs(a), b); //计算最大公约数
numerator = a / c;
denominator = b / c;
}
else {
numerator = a;
denominator = b;
}
if(numerator<0&&denominator<0) {
numerator = -numerator;
denominator = -denominator;
}
else if(denominator<0){
numerator = -numerator;
denominator = -denominator;
}
}
void setNumerator(int a) { //设置分子
if (denominator != 1) {
int c = f(Math.abs(a), denominator); //计算最大公约数
numerator = a / c;
denominator = denominator / c;
}
else {
numerator = a;
}
if(numerator<0&&denominator<0) {
numerator = -numerator;
denominator = -denominator;
}
}
void setDenominator(int b) { //设置分母
if (b != 1) {
int c = f(numerator, Math.abs(b)); //计算最大公约数
numerator = numerator / c;
denominator = b / c;
}
else {
denominator = b;
}
if(numerator<0&&denominator<0) {
numerator = -numerator;
denominator = -denominator;
}
}
int getNumerator() {
return numerator;
}
int getDenominator() {
return denominator;
}
int f(int a,int b) { //求a和b的最大公约数
if(a==0) return 1;
if(a<b) {
int c=a;
a=b;
b=c;
}
int r=a%b;
while(r!=0) {
a=b;
b=r;
r=a%b;
}
return b;
}
public String toString(){
StringBuffer Bf = new StringBuffer();
if (this.numerator % this.denominator == 0){
Bf.append(this.numerator/this.denominator);
}
else {
Bf.append(this.numerator);
Bf.append('/');
Bf.append(this.denominator);
}
String s = new String(Bf);
return s;
}
}
分数计算部分
定义四个方法分别对应加减乘除:
- 加法运算:a/b+c/d,分子等于ad+bc,分母等于bd。
- 减法运算:大致与加法运算相同。
- 乘法运算:(a/b)*(c/d),分子等于ac,分母等于bd。
- 除法运算:(a/b)÷(c/d),分子等于ad,分母等于bc。
使用第一部分的工作完成本部分方法的编写,代码如下:
public class Rationalcalculate {
Rational add(Rational r,Rational l) { //加法运算
int a=r.getNumerator();
int b=r.getDenominator();
int newNumerator=l.numerator*b+l.denominator*a; //计算出新分子
int newDenominator=l.denominator*b; //计算出新分母
Rational result=new Rational();
result.setNumerator(newNumerator);
result.setDenominator(newDenominator);
return result;
}
Rational sub(Rational l,Rational r) { //减法运算
int a=r.getNumerator();
int b=r.getDenominator();
int newNumerator=l.numerator*b-l.denominator*a;
int newDenominator=l.denominator*b;
Rational result=new Rational();
result.setNumerator(newNumerator);
result.setDenominator(newDenominator);
return result;
}
Rational muti(Rational l,Rational r) { //乘法运算
int a=r.getNumerator();
int b=r.getDenominator();
int newNumerator=l.numerator*a;
int newDenominator=l.denominator*b;
Rational result=new Rational();
result.setNumerator(newNumerator);
result.setDenominator(newDenominator);
return result;
}
Rational div(Rational l,Rational r) { //除法运算
int a=r.getNumerator();
int b=r.getDenominator();
int newNumerator=l.numerator*b;
int newDenominator=l.denominator*a;
Rational result=new Rational();
result.setNumerator(newNumerator);
result.setDenominator(newDenominator);
return result;
}
}
算式生成部分
随机生成算式的长度、数字、运算类型和括号,代码如下:
import java.util.*;
public class RamdomObjs {
public String equation(int n) {
StringBuffer Bf = new StringBuffer(200);
int i,roll;
Random rand = new Random();
roll = rand.nextInt(10)+1;
Bf.append(roll);
for(i=0; i< 2*n; i++){
if(i % 2 == 1){
roll = rand.nextInt(10)+1;
Bf.append(roll);
}
else{
roll = rand.nextInt(4)+1;
switch (roll){
case 1:Bf.append('+');break;
case 2:Bf.append('-');break;
case 3:Bf.append('x');break;
case 4:Bf.append('/');break;
}
}
}
roll = rand.nextInt(n/2)+1;
Bf.insert(2*roll,'(');
String s = new String(Bf);
return s;
}
public String testequation(int n) {
char ch[] = new char[2*n];
int a[] = new int[n+1];
int i,j,k=0,roll;
Random rand = new Random();
for(i = 0; i<n+1; i++){
a[i] = rand.nextInt(10)+1;
}
for(i = 0; i<n; i++){
roll = rand.nextInt(4)+1;
switch (roll){
case 1: ch[i] = '+';break;
case 2: ch[i] = '-';break;
case 3: ch[i] = 'x';break;
case 4: ch[i] = '/';break;
}
}
int flag[];
flag = new int[n+1];
for (i=0; i<n+1; i++) {
flag[i] = 1;
}
for (i=0; i<4; i++) {
roll = rand.nextInt(n)+1;
j = 0;
while (j<roll){
if(flag[k%n] == 1){
j++;
}
k++;
}
flag[(k-1)%n] = 0;
k = 0;
}
j = 1;
StringBuffer SB = new StringBuffer();
for (i = 0; i<n+1; i++){
if(flag[i] == 0){
if(j%2 == 1){
SB.append('(');
SB.append(a[i]);
System.out.printf("(%d",a[i]);
}
else {
SB.append(a[i]);
SB.append(')');
System.out.printf("%d)",a[i]);
}
j++;
}
else {
SB.append(a[i]);
System.out.printf("%d",a[i]);
}
if(i<n){
SB.append(ch[i]);
System.out.printf("%c",ch[i]);
}
}
String s = new String(SB);
System.out.printf("\n");
return s;
}
public void testequation1(int n){
int i = 0,j = 0,num = 0,totalnum = 0;
int a[] = new int[2*n+1];
char ch[] = new char[2*n+1];
Random rand = new Random();
StringBuffer SB = new StringBuffer(4*n);
while (i<2*n+1){
if (num > 1 && totalnum < n+1) {
if (rand.nextInt(2) == 0) {
a[i] = rand.nextInt(10) + 1;
SB.append(a[i]);
totalnum++;
num++;
}
else {
switch (rand.nextInt(4)+1){
case 1: ch[i] = '+';break;
case 2: ch[i] = '-';break;
case 3: ch[i] = 'x';break;
case 4: ch[i] = '/';break;
}
a[i] = 0;
SB.append(ch[i]);
num --;
}
}
else if (num < 2) {
a[i] = rand.nextInt(10) + 1;
SB.append(a[i]);
totalnum++;
num++;
}
else {
switch (rand.nextInt(4)+1){
case 1: ch[i] = '+';break;
case 2: ch[i] = '-';break;
case 3: ch[i] = 'x';break;
case 4: ch[i] = '/';break;
}
a[i] = 0;
SB.append(ch[i]);
}
i++;
}
String s = new String(SB);
System.out.println(s);
}
}
计算结果和中缀后缀转换部分
这两步的解释已在代码中进行了注释,不再赘述,其中,计算结果以分数形式得到。
- 计算结果部分:
import java.util.*;
public class Solution {
public Rational evalRPN(String[] tokens) {
//后缀表达式
//建假栈
Rational Re []= new Rational[2*tokens.length];
int flag = 0;
for(int i=0;i<tokens.length&&!tokens[i].equals("");i++){
if (isNumeric(tokens[i])){
int num=Integer.parseInt(tokens[i]);
Re [flag] = new Rational(num,1);
flag++;
Re [flag] = new Rational();
}
else {
//取栈顶元素(出栈)
flag--;
Rational a=new Rational(Re[flag].numerator,Re[flag].denominator);
Re [flag] = new Rational();
Rational b=new Rational(Re[flag-1].numerator,Re[flag-1].denominator);
//calculate(a,b,tokens[i]);
Re [flag-1]=calculate(a,b,tokens[i]);
}
}
//到最后栈里只剩一个元素,所以取栈顶就可以
return Re [0];
}
public Rational calculate(Rational a,Rational b,String opera) {
Rationalcalculate RC = new Rationalcalculate();
switch (opera) {
case "+":
return RC.add(a,b);
case "-":
return RC.sub(b,a);
case "x":
case "*":
return RC.muti(a,b);
case "/":
return RC.div(b,a);
default:
return new Rational();
}
}
public boolean isNumeric(String checkStr) {
try {
Integer.parseInt(checkStr);
return true; // Did not throw, must be a number
} catch (NumberFormatException err) {
return false; // Threw, So is not a number
}
}
}
- 中缀转后缀部分
import java.util.Stack;
import java.util.regex.Pattern;
/**
* 将中缀表达式字符串转换为后缀表达式
*/
public class StringToArithmetic {
// 默认构造
public StringToArithmetic() {
}
// 将中缀表达式转换为后缀表达式
public static String infixToSuffix(String exp) {
// 创建操作符堆栈
Stack<Character> s = new Stack<Character>();
// 要输出的后缀表达式字符串
String suffix = "";
int length = exp.length(); // 输入的中缀表达式的长度
for (int i = 0; i < length; i++) {
char temp;// 临时字符变量
// 获取该中缀表达式的每一个字符并进行判断
char ch = exp.charAt(i);
switch (ch) {
// 忽略空格
case ' ':
break;
// 如果是左括号直接压入堆栈
case '(':
s.push(ch);
break;
// 碰到'+' '-',将栈中的所有运算符全部弹出去,直至碰到左括号为止,输出到队列中去
case '+':
case '-':
while (s.size() != 0) {
temp = s.pop();
if (temp == '(') {
// 重新将左括号放回堆栈,终止循环
s.push('(');
break;
}
suffix += temp;
}
// 没有进入循环说明是当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈
s.push(ch);
break;
// 如果是乘号或者除号,则弹出所有序列,直到碰到加好、减号、左括号为止,最后将该操作符压入堆栈
case '*':
case 'x':
case '/':
while (s.size() != 0) {
temp = s.pop();
// 只有比当前优先级高的或者相等的才会弹出到输出队列,遇到加减左括号,直接停止当前循环
if (temp == '+' || temp == '-' || temp == '(') {
s.push(temp);
break;
} else {
suffix += temp;
}
}
// 没有进入循环说明是当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈
s.push(ch);
break;
// 如果碰到的是右括号,则距离栈顶的第一个左括号上面的所有运算符弹出栈并抛弃左括号
case ')':
// 这里假设一定会遇到左括号了,此为自己改进版,已经验证可以过
// while ((temp = s.pop()) != '(') {
// suffix += temp;
// }
while (!s.isEmpty()) {
temp = s.pop();
if (temp == '(') {
break;
} else {
suffix += temp;
}
}
break;
// 默认情况,如果读取到的是数字,则直接送至输出序列
default:
suffix += ch;
break;
}
}
// 如果堆栈不为空,则把剩余运算符一次弹出,送至输出序列
while (s.size() != 0) {
suffix += s.pop();
}
//
return suffix;
}
}
出题部分(主程序)
- 提示输入题目个数
- 进行作答,答对则提示“你他* 的真是个天才!”,答错则提示“你他* 的答错了”
- 最后根据总的出题数和答对的数目计算正确率。
代码如下:
import java.util.Scanner;
public class Questions {
public static void main(String[] args) {
System.out.println("How many questions do you want?");
Scanner sc = new Scanner(System.in);
int n,i,rights = 0;
n = sc.nextInt();
for (i = 0; i<n; i++){
Test1 test = new Test1();
Rational Ra = test.chuti();
String answer = sc.next();
if(answer.equals(Ra.toString())){
System.out.println("你他娘的还真是个天才!");
rights ++;
}
else {
System.out.println("你他娘的答错了!");
}
}
System.out.printf("你的正确率是%f %%",(float)100.0*rights/n);
}
}
结果截图
结对感受
本周的代码我和搭档各司其职,完成了本次设计任务,其中代码的核心思路由我们双方讨论得出,而代码的设计过程主要由我完成,我的搭档宁心宇在本次任务设计过程中对我起到了很好的辅助作用。