10|成績排序
還沒完成C 或 C++ 皆可CPU 時間上限 1 秒
相關主題: C 基礎速查
C 或 C++ 皆可|CPU 時間上限 1 秒
給你 n 位學生的名字和分數,請把學生排序後輸出:
- 分數高的排前面
- 分數相同時,名字依照 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))
輸入:
5alice 90Bob 85carol 90amy 85Dave 72輸出:
alice 90carol 90Bob 85amy 85Dave 72average 84.40C:
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。