跳到內容

10|成績排序

還沒完成C 或 C++ 皆可CPU 時間上限 1 秒

相關主題: C 基礎速查

C 或 C++ 皆可|CPU 時間上限 1 秒

給你 n 位學生的名字和分數,請把學生排序後輸出:

  1. 分數高的排前面
  2. 分數相同時,名字依照 ASCII 順序小的排前面(也就是 C 的 strcmp、C++ 的 std::string 用 < 比較的順序)

最後再輸出全班的平均分數。

ASCII 順序要注意兩件事:

  • 所有大寫字母都排在小寫字母前面,例如 Bob 排在 amy 前面('B' 是 66,'a' 是 97)
  • 一個名字是另一個名字的開頭時,短的排前面,例如 Ann 排在 Anna 前面

第一行是一個整數 n(1 ≤ n ≤ 100),代表學生人數。

接下來 n 行,每行是一位學生的名字和分數,中間用一個空白隔開:

  • 名字:1 到 20 個英文字母(大寫或小寫),不會有兩個學生的名字完全相同
  • 分數:0 到 100 的整數

輸出 n + 1 行:

  • 前 n 行:排序後的學生,每行是 名字 分數,中間用一個空白隔開
  • 最後一行:average X.XX,其中 X.XX 是平均分數(總分 ÷ n,用 double 計算),印到小數點後 2 位(C 用 %.2f,C++ 用 std::fixed 和 std::setprecision(2))

輸入:

5
alice 90
Bob 85
carol 90
amy 85
Dave 72

輸出:

alice 90
carol 90
Bob 85
amy 85
Dave 72
average 84.40

C:

  • struct:把相關的資料包在一起,例如 struct Student { char name[21]; int score; };(名字最長 20 個字元,再加 1 格放 '\0')
  • struct 陣列:struct Student s[100];,用 s[i].name、s[i].score 存取成員
  • qsort(陣列, 個數, 每個元素的大小, 比較函式)(<stdlib.h>)
  • 比較函式的參數是 const void *,要先轉回 const struct Student * 才能用 -> 取成員
  • 比較函式的回傳值:負數表示第一個參數排前面,正數表示第二個參數排前面,0 表示一樣
  • strcmp(a, b)(<string.h>):a 比較小回傳負數、一樣回傳 0、a 比較大回傳正數

C++:

  • struct Student { std::string name; int score; };,搭配 std::vector<Student>
  • std::sort(v.begin(), v.end(), 比較函式)(<algorithm>)
  • 比較函式可以用 lambda 寫在原地:[](const Student& a, const Student& b) { ... },回傳 true 表示「a 應該排在 b 前面」
  • std::string 可以直接用 <、== 比較
  • 輸出小數:std::cout << std::fixed << std::setprecision(2) << x;(<iomanip>)
提示 1:平均是 84.00,不是 84.40?

如果總分和人數都是 int,sum / n 是整數除法,小數部分在除的時候就被捨去了,之後再轉成 double 也救不回來。

要讓除法本身用 double 計算:(double)sum / n(C++ 可以寫 static_cast<double>(sum) / n)。

提示 2:C 的 qsort 比較函式怎麼寫?
int cmp(const void *pa, const void *pb) {
const struct Student *a = pa; // 從 void * 轉回真正的型別
const struct Student *b = pb;
// 1. 分數不同:分數高的排前面(想想要回傳正數還是負數)
// 2. 分數相同:用 strcmp 比名字
}

分數只有 0 到 100,所以「分數高的排前面」可以直接回傳兩個分數相減的結果,只是要想清楚是誰減誰。

提示 3:C++ 的 lambda 怎麼寫?

lambda 回傳的是「a 是不是應該排在 b 前面」:

std::sort(v.begin(), v.end(), [](const Student& a, const Student& b) {
if (a.score != b.score) {
return a.score > b.score; // 分數高的排前面
}
return /* 名字怎麼比? */;
});

注意比較函式不能用 >= 或 <=,兩個元素「一樣」時一定要回傳 false。