語法書 / AA 競程語法書 下冊 / 第十一單元 / 用 sort 排序 vector 與 string

11.5 用 sort 排序 vector 與 string

sort 收的參數是「開頭位置」與「結尾的下一格位置」——對 vector 來說,這兩個東西你在 10.5 就認識了:begin()end()

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

int main() {
    vector<int> v = {5, 1, 4, 2, 3};

    sort(v.begin(), v.end());                    // 由小到大
    for (int i = 0; i < (int)v.size(); i++) {
        cout << v[i] << ' ';
    }
    cout << '\n';

    sort(v.begin(), v.end(), greater());         // 由大到小也一樣
    for (int i = 0; i < (int)v.size(); i++) {
        cout << v[i] << ' ';
    }
    cout << '\n';
    return 0;
}

執行結果:

1 2 3 4 5
5 4 3 2 1

指標與 iterator 在這裡露出了「同一家人」的身分:陣列用指標當位置、容器用 iterator 當位置,sort 通吃——它只在乎你給它一段「從哪裡到哪裡」的範圍。

反著走:rbegin() 與 rend()

既然 sort 只認「從哪裡到哪裡」,那把範圍反過來給它呢?容器除了 begin()end(),還有一組反向rbegin()rend()rbegin() 指向最後一個元素、rend() 指向第一個元素的前一格,走起來由尾往頭:

sort(v.rbegin(), v.rend());              // 由大到小
sort(v.begin(), v.end(), greater());     // 同一件事的另一種寫法

兩行結果完全相同({3, 1, 2} 兩種寫法都得到 3 2 1),string 也適用。這種寫法在別人的程式碼裡很常見,看到要認得。

string 也能排

string 是字元的容器(10.7),所以 sort(s.begin(), s.end()) 會把字串裡的字元排好——依 ASCII 編號,8.1 的三大區段規則全部適用(數字 < 大寫 < 小寫):

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

int main() {
    string s = "banana";
    sort(s.begin(), s.end());       // 把字串裡的「字元」排序
    cout << s << '\n';
    return 0;
}

執行結果:

aaabnn

「判斷兩個字串是否由相同字母重組而成」這類題目,把兩邊各自排序再比較是否相等,一行 sort 就解決。

vector 排序:先 first,再 second

排序 pair 時,sort 用的還是 <——而 10.11 說過 pair 的比較規則:先比 firstfirst 相同才比 second

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

int main() {
    // (分數, 年齡)
    vector<pair<int,int>> v = {{80, 14}, {95, 13}, {80, 12}, {70, 15}};

    sort(v.begin(), v.end());       // 先比 first,一樣才比 second

    for (int i = 0; i < (int)v.size(); i++) {
        cout << v[i].first << ' ' << v[i].second << '\n';
    }
    return 0;
}

執行結果:

70 15
80 12
80 14
95 13

兩個 80 分的元素靠 second(年齡)分出先後。「主要條件相同時比次要條件」的雙關鍵字排序,用 pair 裝資料就自動到手——這是競程超常用的組合技。

動手試試看:解掉相鄰城市列表——每個城市要把相鄰城市依升序列出。提示:開一個「vector 的陣列」vector<int> adj[100005];,每讀入一條道路就把兩端互相 push_back;輸出前把每個城市的 vector 各自 sort 一次。