日撸Java三百行(day10:综合任务1)

目录

一、题目分析

1.存放学生成绩

2.随机生成成绩

3.找出成绩最好、最差的学生

二、代码实现

1.创建数组,生成随机成绩

2.计算每位同学的总分

3.找出成绩最好、最差的学生

三、Task1.java

 总结


一、题目分析

任务如下:

将学生成绩存放在一个矩阵中,其中行表示学生,列表示科目(例如:第1行即表示第一个学生的语文、数学、英语成绩),要求:

  • 进行学生成绩的随机生成,成绩区间为[50,100]
  • 找出成绩最好、最差的同学,但有挂科的同学不参加评比

1.存放学生成绩

根据题目可知,首先我们需要创建一个二维数组来存放学生的成绩,由于题目要求行代表学生,列代表科目,并且每位同学都统计的是语文、数学、英语三个科目,所以可以创建一个n * 3的二维数组(n代表学生人数)。

2.随机生成成绩

完成数组创建后,下一步就是进行学生成绩的随机生成。随机生成一个学生成绩,其实就是进行随机数生成,而在java中可以通过不同的方式(例如:Math.random类、Random类、SecureRandom类等)来完成随机数生成,这里我们用到的是java中的Random类。

先来了解一下Random类:

(1)Random类有两种构造方式

  • Random():使用一个与当前系统时间对应的数字作为种子数
  • Random(long seed):直接传入一个种子数

注:种子数是生成随机数的第一次使用值,机制是通过一个函数,将种子值转化为随机数空间中的某一个点上,并且产生的随机数均匀散布在空间中。种子数只是随机算法的起源数字,与生成的随机数的范围区间没有任何关系。

(2)Random类提供不同的方法来生成不同种类的随机数

  • nextInt()方法:生成整型的随机数
  • nextDouble()方法:生成实型的随机数

注:在nextInt()、nextDouble()中,小括号里边写生成随机数的范围右边界值(左边界值均为0),特别需要注意这个范围区间是“左闭右开”的,即包括左边界值,不包括右边界值。比如下面的代码所生成的随机数范围就是[0,10)。

Random r = new Random();
int tempNmuber = r.nextInt(10);

如果想要生成范围为[a,b)的随机数,代码如下:

Random r = new Random();
int tempNmuber = a + r.nextInt(b - a);

显然,r.nextInt(b - a)生成随机数的范围为[0,b-a),所以a + r.nextInt(b - a)生成随机数的范围就是[a,b)。

基本了解Random类后,就可以利用其进行学生成绩的随机生成了。

3.找出成绩最好、最差的学生

由于每位学生都有三个科目的成绩,并且同一个学生的三个科目成绩不一定满足正比关系,所以显然我们不能单独用某一个科目的分数高低来评判成绩的好坏。根据经验,利用三个科目的总分或者平均分来进行评比会比较合适,这里我们选择使用的是三个科目的总分。

二、代码实现

1.创建数组,生成随机成绩

由于我们后面需要用到Arrays类与Random类,所以在package语句后,要先进行导包,如下:

package basic;

import java.util.Arrays;
import java.util.Random;

然后,开始创建二维数组data,并利用Random类生成随机成绩,由于这里存放学生成绩的是一个二维数组,所以显然需要用一个两层for循环为每位同学的每科成绩进行生成,如下:

        // Step 1. Generate the data with n students and m courses.
		// Set these values by yourself.
		int n = 10;
		int m = 3;
		int lowerBound = 50;
		int upperBound = 101; // Should be 100.Just use this value for testing.
		int threshold = 60;
		
		// Here we have to use an object to generate random numbers.
		Random tempRandom = new Random();
		int[][] data = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				data[i][j] = lowerBound + tempRandom.nextInt(upperBound - lowerBound);
			} // of for j
		} // of for i

可以看到,在上述代码中设置了upperBound = 101,那为什么这里不设为100而要设为101呢?

这是因为,题目要求的区间为[50,100],左右均为闭区间,但是在上面介绍Random类时,我们已经知道利用Random类生成的随机数的范围是“左闭右开”的,所以为了与题目要求契合,我们将右边界值设为101,使得:

  • tempRandom.nextInt(upperBound - lowerBound)生成随机数的范围 = [0,51)
  • lowerBound + tempRandom.nextInt(uuperBound - lowerBound)生成随机数的范围 = [50,101)

再加上使用的是Random类中的nextInt()方法,它只生成整型的随机数,所以生成的随机数最大只能取到100,这样就可以很好地满足题目所要求的区间[50,100]。

最后,再利用Arrays.deepToString输出该二维数组,如下:

System.out.println("The data is:\r\n" + Arrays.deepToString(data));

2.计算每位同学的总分

首先,需要创建一个一维数组totalScores用于存放每位同学的总分,显然一位同学只有一个总分值,所以该数组totalScores的长度等于data数组的行数n,如下:

int[] totalScores = new int[n];

然后通过两层for循环,计算每位同学的总分,需要注意题目规定有挂科的同学不参加评比,所以为了方便后续操作,这里利用if语句将有挂科的同学的总分赋值为0,如下:

for (int i = 0; i < n; i++) {
   for (int j = 0; j < m; j++) {
      if (data[i][j] < threshold) {
         totalScores[i] = 0;
		 break;
      } // of if
				
      totalScores[i] += data[i][j];
   } // of for j
} // of for i
  • j逐一取值:实现三个科目相加得到总分
  • i逐一取值:得到每位同学的总分

3.找出成绩最好、最差的学生

首先,我们设置两个无效值tempBestIndex、tempWorstIndex,因为总成绩数组totalScores是从0开始索引的,所以令这两个无效值为-1,如果最后这两个变量仍然为-1,则说明找不出成绩最好、最差的学生,代码如下:

// Typical initialization for index:invalid value.
int tempBestIndex = -1;
int tempWorstIndex = -1;

然后,对总成绩最好值、总成绩最差值进行初始化,由于之前将有挂科的同学的总成绩赋值为了0,所以总成绩最好值最小最小可以取到0,而总成绩最差值最大可以取到m * upperBound(即三个科目均拿到满分),因此只需要保证

  • tempBestScore <= 能取到的最小值0
  • tempWorstScore >= 能取到的最大值m * upperBound

初始化设置如下:

// Typical initialization for best and worst values.
// They must be replaced by valid values.
int tempBestScore = 0;
int tempWorstScore = m * upperBound + 1;

再利用for循环对总成绩数组totalScores进行遍历:

  • 将总成绩数组中的值依次与tempBestScore进行比较,并将较大者赋给tempBestScore,较大者在总成绩数组中对应的索引值赋给tempBestIndex
if (tempBestScore < totalScores[i]) {
   tempBestScore = totalScores[i];
   tempBestIndex = i;
} //of if
  • 将总成绩数组中的值依次与tempWorstScore进行比较,并将较小者赋给tempWorstScore,较小者在总成绩数组中对应的索引值赋给tempWorstIndex
if (tempWorstScore > totalScores[i]) {
   tempWorstScore = totalScores[i];
   tempWorstIndex = i;
} // of if

 注意,如果遇到某位同学的总成绩totalScores[ i ]等于0,则需要利用continue跳过本次循环,进入下一次循环,如下:

if (totalScores[i] == 0) {
   continue;
} // of if

 最后,输出成绩最好、最差的学生的总分以及在总成绩数组中的索引值,如下:

// Step 4. Output the student number and score.
if (tempBestIndex == -1) {
   System.out.println("Cannot find best student. All students have failed.");
} else {
	System.out.println("The best student is No." + tempBestIndex + " with scores: " + Arrays.toString(data[tempBestIndex]));
} // of if
		
if (tempWorstIndex == -1) {
	System.out.println("Cannot find worst student. ALL Students have failed.");
} else {
	System.out.println("The worst student is No." + tempWorstIndex + " with scores: " + Arrays.toString(data[tempWorstIndex]));
} // of if

三、Task1.java

完整的程序代码:

package basic;

import java.util.Arrays;
import java.util.Random;

/**
 *This is the tenth code, also the first task.
 *
 *@auther Xin Lin 3101540094@qq.com.
 */

public class Task1 {

	/**
	 *********************
	 *The entrance of the program.
	 *
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String[] args) {
		task1();
	}//of main
	
	/**
	 *********************
	 * Method unit test.
	 *********************
	 */
	public static void task1() {
		// Step 1. Generate the data with n students and m courses.
		// Set these values by yourself.
		int n = 10;
		int m = 3;
		int lowerBound = 50;
		int upperBound = 101; // Should be 100.Just use this value for testing.
		int threshold = 60;
		
		// Here we have to use an object to generate random numbers.
		Random tempRandom = new Random();
		int[][] data = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				data[i][j] = lowerBound + tempRandom.nextInt(upperBound - lowerBound);
			} // of for j
		} // of for i
		
		System.out.println("The data is:\r\n" + Arrays.deepToString(data));
		
		// Step 2. Compute the total score of each student.
		int[] totalScores = new int[n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (data[i][j] < threshold) {
					totalScores[i] = 0;
					break;
				} // of if
				
				totalScores[i] += data[i][j];
			} // of for j
		} // of for i
		
		System.out.println("The total scores are:\r\n" + Arrays.toString(totalScores));
		
		// Step 3. Find the best and worst student.
		// Typical initialization for index:invalid value.
		int tempBestIndex = -1;
		int tempWorstIndex = -1;
		// Typical initialization for best and worst values.
		// They must be replaced by valid values.
		int tempBestScore = 0;
		int tempWorstScore = m * upperBound + 1;
		for (int i = 0; i < n; i++) {
			// Do not consider failed students.
			if (totalScores[i] == 0) {
				continue;
			} // of if
			
			if (tempBestScore < totalScores[i]) {
				tempBestScore = totalScores[i];
				tempBestIndex = i;
			} //of if
			
			// Attention: This if statement cannot be combined with the last one
			// using "else if", because a student can be both the best and worst.
			// I found this bug while setting upperBound = 63.
			if (tempWorstScore > totalScores[i]) {
				tempWorstScore = totalScores[i];
				tempWorstIndex = i;
			} // of if
		} // of for i
		
		// Step 4. Output the student number and score.
		if (tempBestIndex == -1) {
			System.out.println("Cannot find best student. All students have failed.");
		} else {
			System.out.println("The best student is No." + tempBestIndex + " with scores: " + Arrays.toString(data[tempBestIndex]));
		} // of if
		
		if (tempWorstIndex == -1) {
			System.out.println("Cannot find worst student. ALL Students have failed.");
		} else {
			System.out.println("The worst student is No." + tempWorstIndex + " with scores: " + Arrays.toString(data[tempWorstIndex]));
		} // of if
	} // of task1
} // of class Task1

运行结果:

04df620feadf40588cf2ae27101dfceb.png

从以上运行结果可以看到,正如我们预想的那样,对于有挂科的同学其总成绩为0。

通过一系列数据测试,我发现如果将upperBound设为63(使得生成的随机数有更大的几率小于60),那么每个同学都有挂科,每个同学的总分都为0,所以最后的运行结果就是不能找出成绩最好、最差的学生。

 总结

今天通过解决一个综合任务,回顾了if语句、for语句、break语句、continue语句等,同时也学习了生成随机数的方法。今天求成绩最好、最差的处理方式,是将tempBestScore令为可取得的最小值,将tempWorstScore令为可取得的最大值,但是貌似我们也可以直接将总成绩数组中的第一个值令为初始值,再从总成绩数组中的第二个值开始遍历比较,这样好像也可以实现。总之,还是那句话,对于实际的问题,一定要学会拆分问题,分步骤进行代码实现。

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值