11.6 自定義比較函式
greater() 解決了「由大到小」,但排序規則千奇百怪:按絕對值排、按個位數排、偶數優先……這些 sort 都做得到——把你自己寫的比較函式當第三個參數傳進去。
比較函式的規格:
- 恰有兩個參數,型態就是被排序元素的型態;回傳
bool。 - 語意只有一句話:
cmp(x, y)回答「x 是否必須排在 y 前面」。- 必須在前 → 回傳
true。 - x 與 y 相等,或 x 該排在後面 → 回傳
false。
- 必須在前 → 回傳
例如「由大到小」的比較函式,用這句話翻譯:x 比 y 大時,x 必須在前——
bool cmp(int x, int y) {
if (x > y) return true; // x 比 y 大:x 必須排在 y 前面
return false; // 相等或 x 較小:回傳 false
}
if 的條件本身就是要回傳的布林值,所以可以直接簡寫(上冊 7.4 判斷函式的老技巧):
bool cmp(int x, int y) {
return x > y;
}
完整示範:
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int x, int y) {
return x > y; // x 比 y 大時,x 必須排在 y 前面 → 由大到小
}
int main() {
int a[5] = {3, 1, 4, 1, 5};
sort(a, a + 5, cmp); // 用自己的規則排序
for (int i = 0; i < 5; i++) {
cout << a[i] << ' ';
}
cout << '\n';
return 0;
}
執行結果:
5 4 3 1 1
¶各種規則,一招打天下
按絕對值由小到大(abs 是上冊 7.6 的老朋友):
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
bool cmp(int x, int y) {
return abs(x) < abs(y); // 絕對值小的排前面
}
int main() {
int a[5] = {-5, 2, -1, 4, -3};
sort(a, a + 5, cmp);
for (int i = 0; i < 5; i++) {
cout << a[i] << ' ';
}
cout << '\n';
return 0;
}
執行結果:
-1 2 -3 4 -5
按個位數由小到大(% 取餘數,上冊 2.6):
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int x, int y) {
return x % 10 < y % 10; // 個位數小的排前面
}
int main() {
int a[5] = {31, 17, 25, 8, 42};
sort(a, a + 5, cmp);
for (int i = 0; i < 5; i++) {
cout << a[i] << ' ';
}
cout << '\n';
return 0;
}
執行結果:
31 42 25 17 8
¶比較函式裡可以讀全域陣列:排「編號」
一個很重要的進階用法:被排序的可以是「編號」,比較的依據放在全域陣列裡。例如身高存在全域的 height,我們排序的是編號 1 \sim 4:
#include <iostream>
#include <algorithm>
using namespace std;
int height[5] = {0, 160, 155, 170, 158}; // height[i]=編號 i 的身高(1-base)
bool cmp(int x, int y) {
return height[x] < height[y]; // 比的不是編號本身,是編號對應的身高
}
int main() {
int id[4] = {1, 2, 3, 4}; // 要排序的是「編號」
sort(id, id + 4, cmp);
for (int i = 0; i < 4; i++) {
cout << id[i] << ' ';
}
cout << '\n';
return 0;
}
執行結果:
2 4 1 3
編號 2 的身高 155 最矮,所以排最前面。這招的妙處:原始資料完全沒被動過,排好的是「觀看順序」——想再按體重排一次?換一個比較函式、再排一次編號就好,同一份資料要幾種排法有幾種排法。
動手試試看:先解特殊數字排序——題目直接給了主程式,把 cmp 補完就好(偶數優先、偶數由小到大、奇數由大到小:先判斷兩數的奇偶是否相同,再分情況比較)。再挑戰兩種排序——同一批人按身高、按體重各排一次,正是「排編號」的實戰;注意題目對「一樣高/一樣重」的規則,把它寫進比較函式裡(比如身高相同時編號大的在前,就再比一次編號)。