演算法競賽向 C++ Standard Library 使用速查

sun123zxy 發表於 2023-01-24
演算法 C++

因網路上 STL 教程大多零散且缺乏嚴謹性,本文對演算法競賽所需 C++ Standard Library 做了一個較為全面的總結。

全文主要參考以下文件:

如有能力,閱讀原文可獲得更深入的瞭解。

1 STL 演算法

均在 #include<algorithm> 定義。

  • std::sort(first,last,cmp)

    排序為不降序列。

    接受隨機訪問迭代器。可自定義比較函式。

    平均時間複雜度 O(nlogn),C++11 後嚴格 O(nlogn)

  • std::stable_sort(first,last,cmp)

    排序為不降序列,且保持相等元素的順序。

  • std::lower_bound(first,last,val,cmp)

    返回指向首個不小於 val 的元素的迭代器,如無,返回 last

    要求小於 val 的值和大於等於 val 的值分居區間兩側。

    可自定義比較函式。若迭代器支援隨機訪問,對數時間複雜度,否則為線性。

  • std::upper_bound(first,last,val,cmp)

    返回指向首個大於 val 的元素的迭代器,如無,返回 last

  • std::unique(first,last,cmp)

    保留區間中所有連續等值區間的首個元素組成新序列,返回處理後序列的尾迭代器。

    接受前向迭代器,可自定義判斷相等的函式。

    線性時間複雜度。

2 基本或特殊容器

注:C++11 新引入的容器,大部分標頭檔案名與容器名一致。

  • pair #include<utility> :元素對。
  • tuple (C++11) :元組。
  • bitset #include<bitset> :定長壓縮 01 串,可在 O(NK) 的時空複雜度內完成常見運算,K 對應作業系統位數。
  • string #include<string> :字串。

2.1 pair

  • operator= :過載了賦值運算子用於複製。
  • first / second :訪問第一項或第二項。
  • std::make_pair(a,b) :新建元素對,自動檢測型別。
  • operator<=> :過載了各種比較運算子,按第一關鍵字、第二關鍵字順序比較。

2.2 tuple

  • operator= :過載了賦值運算子用於複製。
  • std::get<i>(tp) :獲取元組的第 i 項。
  • std::get<T>(tp) :獲取元組中型別為 T 的項。
  • std::make_tuple(a,b,c,...):新建元組,自動檢測型別。
  • operator<=> :過載比較運算子,同樣是順序關鍵字比較。 …

2.3 string

vector 類似。其餘重要特性如下:

  • c_str() :生成一個 C 風格字串(尾部置 0)並返回其頭部指標。
  • length()size() 的同義函式。
  • append(str) :後方追加字串,返回 *this
  • append(first, last) :區間插入版本。
  • operator+ :連線兩個字串。
  • compare(str) :字典序比較。返回一個 int,用 <0 / ==0 / >0 判斷該字串小於 / 等於 / 大於引數字串。
  • operator<=> :字典序比較的運算子過載。
  • substr(pos=0, count):返回 [pos, min(pos+count, size())) 的子串。時間複雜度與 count 成線性。
  • pop_back() (C++11)
  • find(str) / rfind(str) / find_first_of(c) / find_first_not_of(c) / find_last_of(c) / find_last_not_of(c):找字串或字元,返回位置。若無,返回 npos=-1無時間複雜度保證,不建議使用。

2.4 bitset

bitset<N> bs(val / str):宣告一個長度為 N 的 bitset 並設定初值。

  • & / ! / ^ / ~ / >> / << :支援 AND / OR / XOR / NOT / 右移 / 左移等位運算系列。
  • operator== :判斷兩個 bitset 是否相同。
  • test(idx) / operator[idx] :前者會做越界檢查,丟擲異常。
  • size()
  • count() :返回 1 的個數。
  • all() (C++11) :檢查是否全為 1。
  • any() / none() :檢查是否存在 1 / 沒有 1。
  • set() / reset() :所有位賦 1 / 0。
  • flip() :翻轉 0 / 1。

3 STL 容器概覽

以下部分均為 STL 容器相關內容。

3.1 迭代器

宣告:形如 vector<int>::iterator iter = xxx.begin()。C++11 後可用 auto 代替型別宣告。

*iter 取值,iter++ 後繼。

雙向迭代器可 iter--,隨機訪問迭代器支援加減、比較運算。

  • begin(), end() :返回迭代器。end() 常作為 NULL 使用。
  • cbegin(), cend() (C++11) :部分容器支援,返回只讀迭代器。
  • rbegin(), rend() :部分容器支援,返回反向迭代器。
  • crbegin(), crend() :部分容器支援,返回只讀反向迭代器。

3.2 公共性質

  • operator= :過載了賦值運算子用於複製。
  • empty() :返回容器是否為空,即 v.begin() == v.end()
  • size() :返回容器內元素個數。
  • clear() :清空容器。

4 序列式容器或容器介面卡

序列式容器:

  • array (C++11) :定長順序表,常數隨機訪問。
  • vector #include<vector>:順序表,常數後段插入,常數隨機訪問。
  • deque #include<deque> :順序表,常數雙端插入,常數隨機訪問
  • list #include<list> :連結串列,常數插入刪除,雙向迭代器。
    • forward_list (C++11) :單向版本。

容器介面卡(均不支援迭代器):

  • queue #include<queue>:佇列(FIFO)。適配雙向變長序列式容器,即 deque(預設)或 list
  • stack #include<stack>:棧(LIFO)。適配變長序列式容器,即 deque(預設)、vectorlist
  • priority_queue #include<queue>:大根堆。適配隨機訪問變長序列式容器,即 vector(預設)或 deque

4.1 vector

Find:

  • crbegin()
  • at(idx) / operator[idx] :前者會做越界檢查,丟擲異常。
  • front(), back() :返回首尾元素引用。

Modify:

  • push_back(x) / pop_back() :均攤常數複雜度。
  • insert(iter, val) :於迭代器 iter 處插入,返回指向被插入元素的迭代器。 insert(iter, first, last) :左閉右開區間插入,返回指向首個被插入元素的迭代器。 注意,此操作非常數時間複雜度
  • erase(iter) :於迭代器 iter 處刪除,返回指向被刪除元素的後一個元素的迭代器。 erase(first, last) :左閉右開區間刪除,返回指向被刪除元素的後一個元素的迭代器。 注意,此操作非常數時間複雜度

Size:

  • resize(n) :改變長度,可指定補充元素預設值。
  • shrink_to_fit() :調整為恰好長度。

vector<bool> 被特殊定義,使用方式較為複雜,不建議使用

4.2 deque

  • push_front(x), pop_front()

其餘與 vector 類似。

stack

  • top()
  • push(x)
  • pop()

queue

  • front()
  • push(x)
  • pop()

priority_queue

std::priority_queue<TypeName, Container, Compare>:型別名,底層容器,比較型別。

大根堆,預設用 < 比較大小,即 Compare 傳入 std::less<T>。亦可選擇傳入 std::greater<T> 使用 > 作為比較符號,進而構造出小根堆。

函式同 queue,但 push() / pop() 為對數時間複雜度。

參照 std::less<T> 的實現,自定義比較方式,需傳入一個過載了 operator() 的結構體。

4.3 list

  • 無隨機訪問介面。
  • insert(iter, val) / erase(iter) :插入與刪除變為常數時間複雜度,參見 vector
  • sort(cmp) :為連結串列特殊設計的 O(nlogn) 穩定排序演算法。

其餘與 deque 類似。

5 關聯式容器

不支援隨機訪問,雙向迭代器,大部分操作為對數時間複雜度,紅黑樹實現。

  • set / multiset #include<set>:元素有序。後者支援同值多元素。
  • map / multimap #include<map>:鍵有序。後者支援同鍵值多元素。

5.1 set / multiset

set<Key, Compare>:類似 priority_queue,可自定義比較方式。

Find:

  • crbegin()
  • count(x) :返回值為 x 的元素數量。
  • lower_bound(x) / upper_bound(x) :為 set 特殊定製的對數時間複雜度 lower_boundupper_bound

沒有 nth_element(),對數時間複雜度查詢第 k 大需手寫或使用 pbds 庫。

Modify:

  • insert(x) :插入元素 x。返回 pair<iterator, bool>,表示插入元素的迭代器與插入是否成功。 對於 multiset,由於插入不會失敗,insert 只返回迭代器。
  • erase(x) :刪除所有值為 x 的元素,返回刪除元素的個數。 erase(iter) :刪除迭代器指向的元素,(C++11) 返回指向被刪除元素的後一個元素的迭代器。 erase(first, last):左閉右開區間刪除,(C++11) 返回指向被刪除元素的後一個元素的迭代器。

刪除單個值為 x 的元素,可按如下方法進行:

auto it = s.find(x);
s.erase(it);

5.2 map / multimap

map<Key, T, Compare>:可自定義比較方式。

  • 對迭代器解引用得到 pair<Key, T>
  • insert(pair<Key, T>)
  • at[key] / operator[key]:前者會做越界檢查,丟擲異常。

其餘與 set 類似。

6 無序關聯式容器 (C++11)

單向迭代器,平均常數時間複雜度,Hash 實現。

若不支援 c++11,使用時需引入 TR1 擴充套件。例如,使用 unordered_map 需引入 #include<tr1/unordered_map> 標頭檔案,使用時需寫為 std::tr1::unordered_map

  • unordered_set / unordered_multiset #include<unordered_set>:元素無序。
  • unorderep_map / unordered_multimap #include<unordered_map>:鍵無序。

只有單向迭代器,其餘特性與有序版本類似。

此外,可按如下方法自定義相等判定方式和 Hash 函式。

  • unordered_set<Key, Hash, KeyEqual>
  • unordered_map<Key, T, Hash, KeyEqual>

如上,可自定義 Hash 函式。