1. 程式人生 > >C++ STL 常用演算法

C++ STL 常用演算法

標準庫定義了一組泛型演算法:因為它們實現共同的操作,所以稱之為“演算法”;而“泛型”指的是它們可以操作在多種容器型別上,不但可作用於標準庫型別,還可用在內建陣列型別、甚至其他型別的序列上。大多數演算法是通過遍歷由兩個迭代器標記的一段元素來實現其功能。使用泛型演算法必須包含標頭檔案 algorithm :

   #include <algorithm>

標準庫還定義了一組泛化的算術演算法(generalized numeric algorithm),其命名習慣與泛型演算法相同。使用這些演算法則必須包numeric標頭檔案:

   #include <numeric>

區別帶一個函式引數的演算法版本

:大部分演算法會提供比較或測試函式取代操作符使用的版本,此版本在名字中加了 _if 字尾。

區別是否實現複製的演算法版本:很多演算法將重新排列的元素寫回其輸入範圍。標準庫提供了複製版本,此版本的演算法在名字中添加了 _copy 字尾。

迭代器實參型別

通常泛型演算法都是在標記容器(或其他序列)內的元素範圍的迭代器上操作的。標記範圍的兩個實參型別必須精確匹配,它們必須指向同一個容器中的元素(或者超出容器末端的下一位置),並且如果兩者不相等,則第一個迭代器通過不斷地自增,必須可以到達第二個迭代器。對於帶有兩對迭代器引數的演算法,如find_first_of:每對迭代器中,兩個實參的型別必須精確匹配,但不要求兩對之間的型別匹配

。特別是,元素可儲存在不同型別序列中,只要這兩序列的元素可以比較即可。


一、只讀演算法

查詢演算法


find_if( beg, end, func ) :函式find 的帶一個函式引數的 _if 版本,與 find 功能相同,條件:使函式 func 返回true。

搜尋與統計演算法


count_if( beg, end, func ):函式count 的 _if 版本。 

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

bool evenNum( int n ) //是否為偶數
{ return n % 2; }

void main()
{
    int num = 6;
    vector<int> v1;
    for( int i = 0; i != 10; ++i )
        v1.push_back(i);
    vector<int>::iterator iter = find( v1.begin(), v1.end(), num ); //查詢等於6的元素位置
    if( iter != v1.end() )
        cout << "匹配元素的索引: " << iter - v1.begin() << endl; //找到匹配元素位置6

    vector<int> v2;
    v2.push_back(6); 
    v2.push_back(5);
    v2.push_back(3);
    iter = find_first_of( v1.begin(), v1.end(), v2.begin(), v2.end() ); //第一個匹配元素是3
    if( iter != v1.end() )
        cout << "第一個匹配元素索引:" << iter - v1.begin() << endl; 

    int even_times = count_if( v1.begin(), v1.end(), evenNum ); //謂詞函式引數,偶數個數為5個
    cout << "偶數個數 :" << even_times << endl; 
    
    vector<int> v3;
    v3.push_back(1);
    v3.push_back(1);
    v3.push_back(2);
    v3.push_back(2);
    //v3 非遞減,每次迴圈 iter 跳向第一個大於當前元素的位置,因此只輸出兩個數 1,2
    for( iter = v3.begin(); iter != v3.end(); iter = lower_bound( iter, v3.end(), *iter ) )
        cout << *iter << " ";
}



二、可變序列演算法

可變序列演算法包括元素複製、變換、替換、填充、移除隨機生成等。


copy,transform,fill_n 和 generat 都需要保證:輸出序列有足夠的空間。 

remove函式並不真正刪除元素,只是將要刪除的元素移動到容器的末尾,刪除元素需要容器 erase 函式來操作。同理,unique 函式也不會改變容器的大小,只是這些元素的順序改變了,是將無重複的元素複製到序列的前端,從而覆蓋相鄰的重複元素。unique 返回的迭代器指向超出無重複的元素範圍末端的下一位置。

remove_if( beg, end, func ):remove 的 _if 版本。

replace_if( beg, end, func, v2 ):replace 的 _if 版本。

_copy 版本,注意必須保證輸出序列的大小不小於輸入序列的大小。

remove_copy( beg, end, dest ):remove 的 _copy 版本,將反轉後的序列輸出到從dest 開始的區間。

remove_copy_if( beg, end, dest, func ):remove_copy 的 _if 版本。

replace_copy( beg, end, dest, v1, v2) :replace 的 _copy 版本。

replace_copy_if( beg, end, dest, func, v2 ):replace_copy 的 _if 版本。


三、排序演算法


partial_sort 對區間 [beg, end) 內的 mid - beg 個元素進行排序,將最小的 mid - beg 個元素有序放在序列的前 mid - beg 的位置上。

reverse_copy( beg, end, dest ):reverse 的 _copy 版本。

rotate_copy (beg, mid, end, dest):rotate 的 _copy 版本。


四、關係演算法


標準庫還提供 求最大值、最小值的 max 和 min 函式。

五、堆演算法


vector<int> v;
v.push_back(3);
v.push_back(9);
v.push_back(17);
v.push_back(20);
v.push_back(12);

make_heap(v.begin(),v.end()); //用 vector 代替陣列建立最大堆
cout << "堆: ";
for( vector<int>::iterator iter= v.begin(); iter != v.end(); ++iter )  
    cout << *iter << " ";  
cout<<endl;  

cout << "堆排序後: ";
sort_heap(v.begin(),v.end()); //堆排序
for( vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter )
    cout << *iter << " ";
cout<<endl;


容器特有的演算法

list 容器上的迭代器是雙向的,而不是隨機訪問型別。因此,在此容器上不能使用需要隨機訪問迭代器的演算法。這些演算法包括 sort 及其相關的演算法。還有一些其他的泛型演算法,如 merge、remove、reverse 和 unique,雖然可以用在list 上,但卻付出了效能上的代價。如果這些演算法利用 list 容器實現的特點,則可以更高效地執行。

標準庫為 list 容器定義了更精細的操作集合,使它不必只依賴於泛型操作。


lst.remove_if(func):remove() 的 _if 版本,刪除使func 返回真的元素。