摘要:C++ STL標準模板庫在數據結構和算法的實踐領域發揮着重要做用,極大的提升了開發效率。STL的三大組成部分爲容器、迭代器、算法,本文主要講解STL算法中的變易算法。本文從實踐的角度簡單介紹了一下函數原型和相關函數的使用。ios
C++ STL的變易算法(Mutating Algorithms)是一組能修改容器元素數據的模板函數,可進行序列數據的複製、交換、替換、填充、移除、旋轉、隨機抖動、分割。這些算法函數對迭代器有較高要求,在應用時,先要檢查容器的迭代器是否符合要求,防止產生編譯錯誤。算法
該函數用於容器間元素拷貝,將迭代器區間[first, last)的元素複製到由複製目標迭代器result給定的區間[result, result + (last - first))。數據結構
函數原型以下:less
template<class InputIterator, class OutputIterator> OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
注意:目標容器的容量要比待複製的內容大。dom
下面的示例程序將容器v中的內容複製到容器v2,並打印容器v2的元素。數據結構和算法
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(4); v.push_back(3); vector<int> v2(4); v2.push_back(8); copy(v.begin(), v.end(), v2.begin()); for_each(v2.begin(), v2.end(), print); return 0; }
結果輸出爲:函數
2 4 3 0 8spa
將一個迭代器區間的內容複製到另外一迭代器區間,與copy()類似,不一樣的是複製過程從最後的元素開始。code
函數原型以下:orm
template<class BidirectionalIterator1, class BidirectionalIterator2> BidirectionalIterator2 copy_backward ( BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result )
下面的示例程序將容器v的內容複製到容器v2中,從後往前複製。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(4); v.push_back(3); vector<int> v2(4); v2.push_back(8); copy_backward(v.begin(), v.end(), v2.end()); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
0 0 2 4 3
該函數的功能是實現兩個元素的交換。雖然大多數容器內部都提供了swap函數,這裏提供了更通常的迭代器形式。
函數原型以下:
template <class T> void swap ( T& a, T& b )
下面的示例程序用於交換兩個整數並打印。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main(void) { int a = 2; int b = 3; swap(a, b); cout << a << ", " << b << endl; return 0; }
輸出結果爲:
3, 2
iter_swap函數是swap函數的迭代器形式,使交換算法更易用於通常的容器。
這個函數和上面的swap()有什麼不一樣呢?
函數原型以下:
template <class ForwardIterator1, class ForwardIterator2> void iter_swap (ForwardIterator1 a, ForwardIterator2 b)
下面的示例程序用於交換兩個容器,並打印容器元素。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; vector<int> v2; v.push_back(2); v.push_back(3); v2.push_back(7); v2.push_back(8); v2.push_back(9); swap(v, v2); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
7 8 9
該函數用於兩個迭代器區間元素的交換。
函數原型以下:
template<class ForwardIterator1, class ForwardIterator2> ForwardIterator2 swap_ranges (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2)
下面的示例程序用於容器v與容器v2的前兩個元素交換,並打印交換結果。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; vector<int> v2; v.push_back(2); v.push_back(3); v2.push_back(7); v2.push_back(8); v2.push_back(9); swap_ranges(v2.begin(), v2.end() - 1, v.begin()); for_each(v.begin(), v.end(), print); cout << endl; for_each(v2.begin(), v2.end(), print); cout << endl; return 0; }
輸出結果爲:
7 8
2 3 9
該函數用於容器元素的變換操做。有兩個使用原型,分別用於一元函數對象和二元函數操做。
函數原型以下:
template <class InputIterator, class OutputIterator, class UnaryOperation> OutputIterator transform (InputIterator first1, InputIterator last1, OutputIterator result, UnaryOperation op) template <class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation> OutputIterator transform (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation binary_op)
下面的示例程序將容器v中的元素加倍,並輸出元素的值。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int twice(int x) { return 2 * x; } int main(void) { vector<int> v; v.push_back(2); v.push_back(4); vector<int> v2(v.size()); transform(v.begin(), v.end(), v2.begin(), twice); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
4 8
該函數用於將指定函數值替換爲新值。
函數原型以下:
template <class ForwardIterator, class T> void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value)
下面的示例程序將容器v中值爲5的元素的值替換爲6。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(3); v.push_back(5); v.push_back(8); replace(v.begin(), v.end(), 5, 6); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
3 6 8
該函數是replace函數的謂詞判斷版本,將知足謂詞條件的元素替換爲新值。
函數原型以下:
template <class ForwardIterator, class UnaryPredicate, class T> void replace_if (ForwardIterator first, ForwardIterator last, UnaryPredicate pred, const T& new_value )
下面的示例程序將容器v中值爲偶數的元素的值替換爲2。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int odd(int x) { return !(x % 2); } int main(void) { vector<int> v; v.push_back(3); v.push_back(5); v.push_back(8); replace_if(v.begin(), v.end(), odd, 2); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
3 5 2
該函數先進行元素替換,再將元素複製到新容器。
函數原型以下:
template <class InputIterator, class OutputIterator, class T> OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, const T& val)
下面的示例程序將容器v中值爲5的元素的值替換爲6,並複製到容器v2。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(3); v.push_back(5); v.push_back(8); vector<int> v2(v.size()); replace_copy(v.begin(), v.end(), v2.begin(), 5, 6); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
3 6 8
該函數是replace_copy的一元謂詞判斷版本,用法類似。
函數原型以下:
template <class InputIterator, class OutputIterator, class UnaryPredicate, class T> OutputIterator replace_copy_if (InputIterator first, InputIterator last, OutputIterator result, UnaryPredicate pred, const T& new_value)
下面的示例程序將容器v中值爲偶數的元素的值替換爲2,並複製到容器v2。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int odd(int x) { return !(x % 2); } int main(void) { vector<int> v; v.push_back(3); v.push_back(5); v.push_back(8); vector<int> v2(v.size()); replace_copy_if(v.begin(), v.end(), v2.begin(), odd, 2); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
3 5 2
該函數將同一個值填充到迭代器區間內。
函數原型以下:
template <class ForwardIterator, class T> void fill (ForwardIterator first, ForwardIterator last, const T& val)
下面的示例程序將擁有5個元素的容器v全填充爲9。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v(5); fill(v.begin(), v.end(), 9); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
9 9 9 9 9
與fill函數類似,但可指定填充的元素的個數。
函數原型以下:
template <class OutputIterator, class Size, class T> void fill_n (OutputIterator first, Size n, const T& val)
下面的示例程序將容器v的前3個元素填充爲9。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v(5); fill_n(v.begin(), 3, 9); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
9 9 9 0 0
該函數用於隨機生成函數,將迭代器區間內的元素填充爲生成的元素。
函數原型以下:
template <class ForwardIterator, class Generator> void generate (ForwardIterator first, ForwardIterator last, Generator gen)
下面的程序將生成公比爲3的等比數列。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int next(int x) { return 2; } class Seq { public: int a; Seq() { a = 1; } inline int operator()() { a *= 3; return a; } }; int main(void) { vector<int> v(5); Seq seq; generate(v.begin(), v.end(), seq); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
3 9 27 81 243
該函數與generate類似,只是限定了填入容器的數值個數。
函數原型以下:
template <class OutputIterator, class Size, class Generator> void generate_n (OutputIterator first, Size n, Generator gen)
下面的示例程序將容器v的前3個元素填充爲僞隨機數。
#include <iostream> #include <vector> #include <algorithm> #include <cstdlib> #include <ctime> using namespace std; void print(int x) { cout << x << " "; } int getRand(void) { return (rand() % 100); } int main(void) { vector<int> v(6); srand(unsigned(time(0))); generate_n(v.begin(), 3, getRand); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
48 19 84 0 0 0
該函數用於將容器中等於某個給定值的元素所有移除掉,並返回表示容器結束位置的迭代器。
函數原型以下:
template <class ForwardIterator, class T> ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
下面的示例程序將容器v中值爲3的元素移除掉了,並把剩餘元素打印出來。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(3); v.push_back(5); vector<int> v2(4); vector<int>::iterator result = remove(v.begin(), v.end(), 3); for_each(v.begin(), result, print); return 0; }
輸出結果爲:
2 5
該函數是remove函數的一個帶謂詞判斷的版本,將知足一元謂詞判斷條件的元素移除掉。
函數原型以下:
template <class ForwardIterator, class UnaryPredicate> ForwardIterator remove_if (ForwardIterator first, ForwardIterator last, UnaryPredicate pred)
下面的示例程序將容器v中值爲偶數的元素移除掉了。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int isOdd(int x) { return !(x % 2); } void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(3); v.push_back(7); v.push_back(8); vector<int>::iterator result = remove_if(v.begin(), v.end(), isOdd); for_each(v.begin(), result, print); return 0; }
輸出結果爲:
3 7
該函數先進行元素移除,再將元素複製到新容器,實質上是一個條件複製。
函數原型以下:
template <class InputIterator, class OutputIterator, class T> OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, const T& val)
下面的示例程序將容器v中值不爲3的元素複製到新容器v2。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(3); v.push_back(5); vector<int> v2(4); remove_copy(v.begin(), v.end(), v2.begin(), 3); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
2 5 0 0
該函數是remove_copy的一個帶謂詞判斷版本,將不知足一元謂詞判斷條件的元素複製到新容器。
函數原型以下:
template <class InputIterator, class OutputIterator, class UnaryPredicate> OutputIterator remove_copy_if (InputIterator first, InputIterator last, OutputIterator result, UnaryPredicate pred)
下面的示例程序將容器v中值不是偶數的元素複製到新容器v2中。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int isOdd(int x) { return !(x % 2); } void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(3); v.push_back(7); v.push_back(8); vector<int> v2(5); remove_copy_if(v.begin(), v.end(), v2.begin(), isOdd); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
3 7 0 0 0
該函數用於剔除容器中連續重複的元素,只保留一個。有兩個使用原型,可使連續重複的原型,或不連續但知足二元謂詞判斷條件的元素。
函數原型以下:
template <class ForwardIterator> ForwardIterator unique (ForwardIterator first, ForwardIterator last) template <class ForwardIterator, class BinaryPredicate> ForwardIterator unique (ForwardIterator first, ForwardIterator last, BinaryPredicate pred)
下面的示例程序將容器v中連續重複元素剔除。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(2); v.push_back(3); v.push_back(5); vector<int>::iterator result = unique(v.begin(), v.end()); for_each(v.begin(), result, print); return 0; }
輸出結果爲:
2 3 5
該函數用於複製不連續重複的元素。一樣有兩個使用原型。
函數原型以下:
template <class InputIterator, class OutputIterator> OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result) template <class InputIterator, class OutputIterator, class BinaryPredicate> OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred)
下面的示例程序將容器v中連續重複元素剔除,並複製到新容器v2。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(3); v.push_back(3); v.push_back(5); vector<int> v2(4); unique_copy(v.begin(), v.end(), v2.begin()); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
2 3 5 0
該函數用於容器元素的反向排列。
函數原型以下:
template <class BidirectionalIterator> void reverse (BidirectionalIterator first, BidirectionalIterator last)
下面的示例程序將容器v中的元素反向排列並打印。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(3); v.push_back(5); reverse(v.begin(), v.end()); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
5 3 2
該函數用於反向複製容器元素。
函數原型以下:
template <class BidirectionalIterator, class OutputIterator> OutputIterator reverse_copy (BidirectionalIterator first, BidirectionalIterator last, OutputIterator result)
下面的實例程序將容器v中的元素反向複製到新容器v2中。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; v.push_back(2); v.push_back(3); v.push_back(5); vector<int> v2(v.size()); reverse_copy(v.begin(), v.end(), v2.begin()); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
5 3 2
該函數用於旋轉某個迭代器區間的元素。
假設區間元素爲{a0, a1, ..., ak, ..., an},ak爲middle位置,則旋轉複製後,新區間元素爲{ak, ak+1, ..., an, a0, a1, ..., ak-1}。
函數原型以下:
template <class ForwardIterator> void rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last)
下面的示例程序將容器v以值爲7的元素爲支點旋轉。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; for(int i = 0; i < 10; i++) { v.push_back(i + 1); } rotate(v.begin(), find(v.begin(), v.end(), 7), v.end()); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
7 8 9 10 1 2 3 4 5 6
該函數經過複製的方法實現旋轉,比rotate函數更簡單高效,但須要佔用較多的內存空間。
函數原型以下:
template <class ForwardIterator, class OutputIterator> OutputIterator rotate_copy (ForwardIterator first, ForwardIterator middle, ForwardIterator last, OutputIterator result)
下面的示例程序將以容器v中值爲7的元素爲支點旋轉,將結果存儲在容器v2中。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; for(int i = 0; i < 10; i++) { v.push_back(i + 1); } vector<int> v2(v.size()); rotate_copy(v.begin(), find(v.begin(), v.end(), 7), v.end(), v2.begin()); for_each(v2.begin(), v2.end(), print); return 0; }
輸出結果爲:
7 8 9 10 1 2 3 4 5 6
該函數用於對容器元素進行隨機的排列,有兩個使用原型,使用C標準的僞隨機函數rand或自定義的隨機數發生器函數對象。
函數原型以下:
template <class RandomAccessIterator> void random_shuffle (RandomAccessIterator first, RandomAccessIterator last) template <class RandomAccessIterator, class RandomNumberGenerator> void random_shuffle (RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& gen)
下面的示例程序將容器v中元素隨機抖動2次並打印,其實這是一個僞隨機抖動的過程。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int main(void) { vector<int> v; for(int i = 0; i < 10; i++) { v.push_back(i); } random_shuffle(v.begin(), v.end()); for_each(v.begin(), v.end(), print); cout << endl; random_shuffle(v.begin(), v.end()); for_each(v.begin(), v.end(), print); return 0; }
輸出結果爲:
8 1 9 2 0 5 7 3 4 6
7 0 6 3 2 8 1 4 5 9
該函數用於從新分割排列容器的元素,按照醫院謂詞判斷條件,分割成知足和不知足條件的兩部分,返回的迭代器指向首個不知足條件的元素。
函數原型以下:
template <class BidirectionalIterator, class UnaryPredicate> BidirectionalIterator partition (BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate pred)
下面的示例程序將容器v中的元素分爲小於5和大於等於5的兩部分,並分別將元素打印出來。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int less5(int x) { if(x < 5) { return 1; } else { return 0; } } int main(void) { vector<int> v; for(int i = 10; i > 0; i--) { v.push_back(i); } vector<int>::iterator iv = partition(v.begin(), v.end(), less5); cout << "less than 5: "; for_each(v.begin(), iv, print); cout << endl; cout << "no less than 5: "; for_each(iv, v.end(), print); return 0; }
輸出結果爲:
less than 5: 1 2 3 4
no less than 5: 6 5 7 8 9 10
該函數與parition相似,從新分割排列容器的元素,但能夠保持原有元素的前後順序。
函數原型以下:
template <class BidirectionalIterator, class UnaryPredicate> BidirectionalIterator stable_partition (BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate pred)
下面的示例程序也是將容器v中的元素分爲小於5和大於等於5的兩部分,但保持元素的穩定性。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void print(int x) { cout << x << " "; } int less5(int x) { if(x < 5) { return 1; } else { return 0; } } int main(void) { vector<int> v; for(int i = 10; i > 0; i--) { v.push_back(i); } vector<int>::iterator iv = stable_partition(v.begin(), v.end(), less5); cout << "less than 5: "; for_each(v.begin(), iv, print); cout << endl; cout << "no less than 5: "; for_each(iv, v.end(), print); return 0; }
輸出結果爲:
less than 5: 4 3 2 1
no less than 5: 10 9 8 7 6 5
本文主要介紹了STL算法庫中的變易算法(Mutating Algorithms),是一些會使操做數據發生改變的算法,包括:
這些函數均包含於頭文件,本文給出的全部代碼在VS2010中編譯運行經過。
[1] http://www.cplusplus.com/reference/algorithm/, - C++ Reference;
[2] C++ STL開發技術導引, 葉志軍, 人民郵電出版社.
(全文完)