Java Homework - 學生分數排序器

 Java 班第四份 Java 作業的其中一題,給定 n 個學生在 m 次考試內的所有成績,求每位學生取得單次考試內最高分的次數。原題目有給出 8 個學生考 6 次考試的每個分數 (共 48 個),不過我是寫了個隨機分數產生器 randomAllScores(m, n),方便測試用。

作法

首先,考量方便直接從一次考試的所有分數內找出最高的分數,randomAllScores() 產生的二維陣列 allScores,設計成:

 {考試 1:{學生 1 分數, 學生 2 分數, 學生 3 ...}, 考試 2:{ ... }, ... ... }

再來準備了一組外層是學生個數,內層含學生編號和次數紀錄的二維陣列 studentRecords ,用於最後結果輸出。

計算過程,利用迴圈從全部分數按考試取得 highest 這個整數陣列,表示同學裡誰拿最高分。若是某學生的分數最高,則將該學生的元素 + 1 表示,例如 {0, 0, 1, 0, 0, 0, 0, 0} 即代表考最高分的是第三個學生。之後便可將這陣列的所有元素按順序加到 studentRecords 裡每個學生的次數元素,有加到 1 便是最高分次數加一次。所有考試都執行過這組動作即完成計算,最後輸出。

由於取得 highest 的 studentsWithHighestScore() 會檢查所有的學生分數 (迴圈),然後 hasHighestScore() 每檢查一個便會拿該分數跟所有分數比較 (迴圈內再迴圈),顯然這是個沒有特別技巧的暴力解法:計算步驟為 n^2。當學生人數 n 很大時,程式的效率並不好。

用 array、rank、largest element 等關鍵字搜尋可以查到很多相關題型的作法,目前看到最順眼的是 GeeksforGeeks 這篇 k largest (or smallest) elements in an array 裡的 quick sort 作法,之後研究怎麼應用到這一題。


package junli.hw4;

public class StudentScoreRanker {

    public static void main(String[] args) {
        // Set up data 
        int[] numOfStudents = 8;
        int[][] allScores = randomAllScores(6, numOfStudents);      
        int[][] studentRecords = prepareRecordArray(numOfStudents);
//        System.out.println("All scores: " + Arrays.deepToString(allScores));

        // Process 
        for(int i = 0; i < allScores.length; i++) {
            int[] highest = studentsWithHighestScore(allScores[i]);
//            System.out.println(Arrays.toString(highest));

            addHighestRecord(highest, studentRecords);
        }
        
        // Output
        System.out.println("學員\t 最高分次數");
        for(int i = 0; i < studentRecords.length; i++) {
            System.out.printf("  %d:\t\t%d\n", studentRecords[i][0], studentRecords[i][1]);
        }

    }

    private static void addHighestRecord(int[] highest, int[][] studentRecords) {
        for(int i = 0; i < highest.length; i++) {
            studentRecords[i][1] += highest[i];
        }
    }

    private static int[] studentsWithHighestScore(int[] test) {
        int[] array = new int [test.length];
        for(int i = 0; i < test.length; i++) {
            if(hasHighestScore(test, test[i])) {
                array[i] += 1;
            }
        }
        return array;
    }

    private static boolean hasHighestScore(int[] test, int score) {
        for(int i = 0; i < test.length; i++) {
            if(test[i] > score) {
                return false;
            }
        }
        return true;
    }
    
    private static int[][] prepareRecordArray(int numOfStudents) {
        int[][] array = new int [numOfStudents][2];
        for(int i = 0; i < numOfStudents; i++) {
            int[] r = {i + 1, 0};
            array[i] = r;
        }
        return array;
    }

    private static int[][] randomAllScores(int numOfTests, int numOfStudents) {
        int[][] twoDiArray = new int [numOfTests][numOfStudents];
        for(int i = 0; i < numOfTests; i++) {
            for(int j = 0; j < numOfStudents; j++) {
                twoDiArray[i][j] = randomNumInRange(0, 100);
            }
        }
        return twoDiArray;
    }

    private static int randomNumInRange(int min, int max) {
        return (int) (Math.random() * (max - min + 1) + min);
    }

}

留言

這個網誌中的熱門文章

那天