語法書 / AA 競程語法書 下冊 / 第十三單元 / pair 還是結構體?

13.8 pair 還是結構體?

走到這裡,「綁成一包」的工具你有兩個:10.11 的 pair 和本單元的結構體。什麼時候用哪個?先看一個兩邊都做得到的任務,親手感受差別。

任務:有 N 家餐廳,每家有所在城市(字串)、你給的評分(整數,互不相同)、編號 1 \sim N。請照「城市字典序由小到大、同城市評分由高到低」的順序,輸出餐廳編號。

pair 路線:要排的是(城市、評分、編號)三個值——pair 塞不下三個?硬塞有一招:pair 套 pair。「評分要由高到低」又是一關——pair 內建的比較只會由小到大,再加一招「取負號」:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<pair<pair<string, int>, int>> v;    // ((城市, 負的評分), 編號)
    for (int i = 1; i <= n; i++) {
        string s;
        int p;
        cin >> s >> p;
        v.push_back({{s, -p}, i});             // 評分取負號:負得越多=原本分數越高
    }
    sort(v.begin(), v.end());                  // pair 內建比較:先 first 再 second
    for (int i = 0; i < n; i++) {
        cout << v[i].second << '\n';
    }
    return 0;
}

結構體路線:三個欄位各有名字,排序規則寫成 operator <

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

struct restaurant {
    string city;     // 城市
    int score;       // 評分
    int id;          // 編號

    bool operator < (const restaurant &b) const {
        if (city != b.city) {
            return city < b.city;     // 城市字典序小的在前
        }
        return score > b.score;       // 同城市:評分高的在前
    }
};

int main() {
    int n;
    cin >> n;
    vector<restaurant> v;
    for (int i = 1; i <= n; i++) {
        restaurant r;
        cin >> r.city >> r.score;
        r.id = i;
        v.push_back(r);
    }
    sort(v.begin(), v.end());
    for (int i = 0; i < n; i++) {
        cout << v[i].id << '\n';
    }
    return 0;
}

拿同一筆測試資料餵兩個版本:

6
kaohsiung 20
taipei 10
hualien 50
hualien 35
taipei 60
kaohsiung 40

執行結果(兩個版本完全相同):

3
4
6
1
5
2

答案一樣、行數也差不多——差別全在讀起來。pair 版的 v[i].first.second 是什麼?-p 為什麼要負?三層大括號哪層是哪層?每個問題都要停下來想;結構體版的 cityscoreid,加上一個把規則寫成白話的 operator <,兩週後回來看照樣秒懂。還有一個硬傷:「取負號」只對數值有效——如果次要排序鍵換成字串(例如平手時比店名),pair 版就變不出來了,而 operator < 想寫什麼規則都行。

決策指南

情況 建議 理由
恰兩個值,要的正是「先比第一、再比第二」 pair 比較規則內建,一行都不用寫
臨時湊一包、只活幾行就丟 pair {x, y} 隨手就綁
三個值以上 struct pair 套 pair 能硬撐,但可讀性直線下降
要自訂比較規則(由大到小、多鍵、字串鍵) struct operator < 想怎麼寫就怎麼寫
這包資料到處被使用、活得很久 struct 成員有名字,程式自帶說明書

猶豫的時候選結構體——多打三行定義,換之後每一行都好讀;pair 留給「兩個值、字典序、用完即丟」的場合。

動手試試看:解掉餐廳指南——本節的任務就是照這題的規則設計的。pair 和結構體兩條路線都親手寫一遍再提交,感受哪邊順手。