標籤:c++ algorithm
在 STL 中,演算法是一系列的函數模版。STL 提供了大概 70 個演算法,由標頭檔 <algorithm>、<numeric>、<functional>組成。
- 標頭檔 <algorithm> 是最大的一個,裡面常用到的功能有:尋找、排序、修改、移除、交換、合并等;
- 標頭檔 <numeric> 較小,主要包括數序運算的函數模版;
- 標頭檔 <functional> 中則定義了一些類模版,來聲明函數對象;
演算法的分類:
- 演算法按其實現的功能可分為 8 類:尋找、排序、數值計算、比較、集合、容器管理、統計和對操作。
- 演算法按對容器的影響可分為 4 類:非修正、修正、排序、數值計算。
非修正演算法非修正即不對容器中元素做修改,是唯讀操作。如:find()、count()、equal()、for_each()、search()等。具體如下:
adjacent_find #尋找相同的相鄰元素 反悔第一個元素的迭代器find #尋找元素 還有find系列尋找函數find_first_offind_endfind_last_ofcount #統計相同元素的個數count_ifmismatch #返回 pair<第一個序列的迭代器,第二個序列的迭代器> 表明第一處不相符合的位置equal #比較容器中的元素是否相同for_each #常用,遍曆序列並對序列中每個元素採用仿函數中定義的操作search #返回迭代器,第一次出現序列2或者某元素的位置search_n #前n次連續出現某元素或者合格第一個位置
修正演算法
修正演算法即對容器中元素做修改,需要寫操作。如:copy()、remove()、reverse()、swap()、unique()等。具體如下:
copy #複製元素到目的容器copy_backward #從後往前複製fill #用某元素填充容器fill_ngenerate #把仿函數產生的結果依次複製到容器中generate_npartition #以仿函數為標準,把容器分成前後兩部分,前半部分是能使仿函數返回真的元素,後半返回假stable_partitionrandom_shuffle #對容器中的元素進行隨機排列remove #刪除某一範圍內的元素,注意:移除的元素被放到容器末尾,還是可以用迭代器遍曆到,函數返回移除後容器的末尾remove_iferase #擦除區間內所有的元素replace #在規定區間內把某值換成新值replace_ifreplace_copy #把區間內元素複製到目的地並且把其中某些元素替換成新值replace_copy_ifrotate #把middle-end的元素放到first的位置上rotate_copyswap #元素的交換swap_rangestransform #把元素按照仿函數中內容轉換unique #保證相鄰元素間沒有相同的,可以加仿函數做為判斷依據,返回最後一個位置的迭代器unique_copy
排序演算法排序需要移動元素,所以需要用到隨機訪問迭代器 RadomAccessIterator,並且指定 [begin,end) 這個排序的前開後閉區間,且按照需要可自己定義比較函數做參數傳入。
常見容器的排序
- vector 和 deque,還有數組,支援隨機存取,可以用 algorithm 中的排序;
- list 容器是雙向鏈表,不支援隨機訪問迭代器,內建了一種穩定排序方法,用的是自底向上的歸併排序;
- map 和 set 底層是紅/黑樹狀結構,本身就是有序儲存;
常用的排序函數
sort #對給定區間所有元素進行排序,用的是快排stable_sort #穩定排序,保證值相等的元素排序後相對位置不變,用歸併排序實現partial_sort #部分排序,保證前n個值有序並且後面的值不在前n個值的範圍內,但後面的值不保證有序,堆排序實現partial_sort_copy #對給定區間複製並排序nth_element #把第n個元素放到第n個位置上去,比他大的都在後,比他小的都在前,但各自都不保證有序is_sorted #判斷一個區間是否已經排好序partition #使得符合某個條件的元素放在前面stable_partition #相對穩定的使得符合某個條件的元素放在前面
常用的比較函數
less #小於(預設比較函數)greater #大於equal_to #等於less_equal #小於等於greater_equal #大於等於
自訂比較大小
使用時不能直接寫入仿函數的名字,而是要寫其重載的()函數,如 less<int>()。下面是 stl 中的 less 的部分源碼:
template <class _Tp>struct less : public binary_function<_Tp,_Tp,bool>{ bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }};
對於基礎資料型別 (Elementary Data Type)和string 可以使用 stl 中現成的函數模版,對於自己定義的類,可以通過自己寫比較函數或重載 < 操作符來實現。其中,重載 < 運算子相當於間接的用到了內建的 less
小例子
#include <iostream>#include <vector>#include <algorithm>using namespace std;class Test {public: Test(int a):a(a){}; int a; bool operator <(const Test &k) const { return a < k.a; }};int main(){ vector<Test> a; a.push_back(Test(2)); a.push_back(Test(3)); a.push_back(Test(1)); vector<Test>::iterator iter; sort(a.begin(), a.end()); for(iter = a.begin(); iter != a.end(); ++iter){ cout<< iter->a <<" "; } // 輸出排序後:1 2 3}
數值計算數值計算函數
數值計算演算法主要針對容器中元素,如 accumulate()、inner_product()、partial_sum()、adjacent_difference()和一些推廣的數值演算法。具體:
accumulate #遍曆求和,也可以用仿函數求其他數值inner_product #內積,相應位置相乘再相加partial_sum #部分元素之和,把結果放到後一容器中,後一容器的第n個元素師前一容器的前n個容器元素之和adjacent_difference #相鄰元素之差,把結果放到後一容器中
小例子
#include <iostream>#include <functional>#include <numeric>#include <vector>using namespace std;int main() { int a[3] = { 2, 2, 3 }; int re = accumulate(a, a + 3, 0); cout << re << endl; // 7, 累加 vector<int> b; b.push_back(2); b.push_back(2); b.push_back(3); int re1 = accumulate(b.begin(), b.end(), 0, plus<int>()); cout << re1 << endl; // 7, 累加 int re2 = accumulate(b.begin(), b.end(), 1, multiplies<int>()); cout << re2; // 12, 累乘}
有序容器、堆、集合
binary_search #二分法搜尋,在有序容器中提高搜尋速度lower_bound #返回第一次出現該元素的位置upper_bound #返回最後一次出現該元素的後一位置equal_range #返回pair<lower_bound,upper_bound>inplace_merge #將連貫有序序列合并merge #合并兩個容器includes #判斷某區間內所有的元素是否在另一區間中#堆操作push_heappop_heapsort_heapmake_heap#集合操作set_intersectionset_differenceset_symmetric_difference#最值min #最小max #最大min_element #最小位置的迭代器max_element #最大位置的迭代器lexicograplical_compare #範圍內的字典序比較,前後序列的比較next_permutation prev_permutation #上一個/下一個全排列
STL 筆記(五) 演算法 algorithm