從語言的角度看:ios
Algorithm 和 Container 之間沒有直接的聯繫,Algorithm 沒法得知 Container 都有什麼信息,因此須要經過 Iterator 來獲取內部的信息,因此 Iterator 就必需要與 Algorithm 之間有這必定的交接規則,這樣 Iterator 才能適配 Algorithm 的操做。算法
Algorithm的大概形式以下:dom
template<typename Iterator> Algorithm(Iterator itr1, Iterator itr2) { ... } template<typename Iterator, typename Cmp> Algorithm(Iterator itr1, Ilerator itr2, Cmp comp) { ... }
各類容器的 iterators 有5種 iterator_category函數
struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag{}; struct bidirectional_iterator_tag : public forward_iterator_tag{} struct random_access_iterator_tag : public bidirectional_iterator_tag{}
Input 迭代器只能向前移動,一次一步,客戶只有可讀取(不能塗寫)他們所指的東西,並且只能讀取一次。它們模仿指向輸入文件的閱讀指針;C++ 程序庫中的istream_iterator是這一分類的表明。指針
Ouput 迭代器狀況相似,但一切只爲輸入:它們只能向前移動,一次一步,客戶只可塗寫它們所指的東西,並且只能塗寫一次。它們模仿指向輸出文件的塗寫指針;ostream_iterator是這一分類的表明。code
Forward 迭代器,這種迭代器能夠作前兩種迭代器的每一件事,並且能夠讀或寫其所指物一次以上。這使得他們可施行於屢次性操做算法。STL並未提供單向linked list,但某些程序庫有(slist),而這種容器的迭代器就屬於 forward 迭代器。繼承
Bidirectional 迭代器,除了能夠向前移動,還能夠向後移動。STL的list迭代器就屬於這一分類,set, multiset,map 和 multimap 的迭代器也都是這一分類。input
random_access 迭代器能夠在常量時間內向前或者向後跳躍任意距離。這樣的算術很相似指針算術。源碼
首先是一個distance迭代器之間距離的算法,distance算法經過對迭代器分類的判斷分別調用不一樣的實現函數。其中,由於迭代器的分類有繼承關係,再根據函數匹配的原則,不一樣分類的迭代器會自動選擇適合的實現方法。it
template <class InputIterator> inline iterator_traits<InputIterator>::difference_type distance(InputIterator first, InputIterator last){ typedef typename iterator_traits<InputIterator>::iterator_category category; return __distance(first, last, category()); } template<class InputIterator> inline iterator_traits<InputIterator>::difference_type __distance(InputIterator first, InputIterator last, input_iterator_tag){ iterator_traits<InputIterator>::difference_type n =0; while(first != last){ ++first; ++n; } return n; } template <class RandomAccessIterator> inline iterator_traits<RandomAccessIterator>::difference_type __distance(RandomAccessIterator first, RandomAccessIterator last, random_access_iterator_tag){ return last - first; }
與distance相似的算法舉例:
template<class InputIterator, class Distance> inline void advance(InputIterator& i, Distance n){ __advance(i, n, iterator_category(i)); } //此方法與iterator_traits<InputIterator>::iterator_category一致 template <class Iterator> inline typename iterator_traits<Iterator>::iterator_category iterator_category(const Iterator&){ typedef typename iterator_traits<Iterator>::iterator_category category; return category(); } template<class InputIterator, class Distance> inline void __advance(InputIterator& i, Distance n, input_iterator_tag){ while(n--) ++i; } template<class BidirectionalIterator, class Distance> inline void __advance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag){ if(n >= 0) while(n--) ++i; else while(n++) --i; } template<class RandomAccessIterator, class Distance> inline void __advance(RandomAccessIterator& i, Distance n, random_accrss_iterator_tag){ i += n; }
算法沒法強制要求傳入指定類型的迭代器,由於算法是一種模板,因此理論上能夠傳入全部類型的參數。爲了儘量保證算法正常工做,算法會「暗示」使用者出入怎樣類型的迭代器。具體的實現是經過在 template<class RandomAccessIterator, class Distance>
這其中的 RandomAccessIterator
就是對傳入類型的「暗示」。
template <class InputIterator, class T> T accumulate(InputIterator first, InputIterator last, T init) { for(;first != last; ++first) init = init + *first;//將元素累加至初值init身上 return init; } template <class InputIterator, class T, class BinaryOperation> T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op) { for(;first != last; ++first) init = binary_op(init, *first); return init; }
一般算法會有兩個版本,一個版本適用默認的規則,另外一個版本可讓用戶傳入一個自定義的「規則」。
accumulate 使用的例子:
#include <iostream> //std::out #include <functional> //std::minus #include <numeric> //std::accumulate int myfunc(int x, int y) { return x + 2 * y;} //function object struct myclass{ int operator()(int x, int y) { return x + 3 * y;} } myobj; int main() { int init = 100; int nums[] = {10, 20, 30}; cout << "using default accumulate:"; cout << accumulate(nuyms, nums+3, init); //160 cout << "\n"; cout << "using functional's minus:"; cout << accumulate(nuyms, nums+3, init, minus<int>()); //40 cout << "\n"; cout << "using custom function:"; cout << accumulate(nuyms, nums+3, init, mufunc); //220 cout << "\n"; cout << "using custom object:"; cout << accumulate(nuyms, nums+3, init, myobj); //280 cout << "\n"; }
針對容器中的每個元素都進行一次操做
template <class InputIterator, class Function> Function for_each(InputIterator first, InputIterator last, Function f) { for(; first != last; ++first) f(*first); return f; }
replace:範圍內全部等於old_value
的元素都以new_value
替換
template <class ForwardIterator, class T> void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value){ for(;first != last; ++first) if(*first == old_value) *first = new_value; }
replace_if:範圍內全部知足pred()
的元素都以new_value
替換
template <class ForwardIterator, class Predicate, class T> void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value){ for(;first != last; ++first) if(pred(*first)) *first = new_value; }
replace_copy:範圍內全部等於old_value
的元素都以new_value
放入新的空間內
template <class ForwardIterator, class T> void replace(ForwardIterator first, ForwardIterator last, OutputIterator result, const T& old_value, const T& new_value){ for(;first != last; ++first, ++result) *result = *first == old_value ? new_value : *first; return result; }
count:統計等於value
的元素個數
template <class InputIterator, class T> typename iterator_traits<InputIterator>::difference_type count(InputIterator first, InputIterator last, const T& value){ typename iterator_traits<InputIterator>::difference_type n = 0; for(; first != last; ++first) if(*first == value) ++n; return n; }
count_if:統計知足pred()
的value
的元素個數
template <class InputIterator, class Predicate> typename iterator_traits<InputIterator>::difference_type count_if(InputIterator first, InputIterator last, Predicate pred){ typename iterator_traits<InputIterator>::difference_type n = 0; for(; first != last; ++first) if(pred(*first)) ++n; return n; }
以上顯示的標準庫中的算法,有些容器使用標準庫的算法效果不是很好或者效率不夠高,那麼這些容器會在成員函數中加入同名的函數。不帶成員函數count()
的容器有:array, vector, list, forward_list, deque
;帶成員函數count()
的容器有:set/multiset, map/multimap, unordered_set/unordered_multiset, unordered_map/unordered_multimap
。經過分析發現自帶成員函數的這些容器都是關聯性容器,能夠依據key
快速查找到value
,因此實現本身特有的函數速度會更快。
find:循環遍歷查找
template <class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, const T& value) { while(first != last && *first != value) ++first; return first; }
find_if:根據條件循環遍歷查找
template <class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, Predicate pred) { while(first != last && !pred(*first)) ++first; return first; }
與count()
同樣,關聯性容器有本身特有的find()
成員函數。
二分查找,前提是已是有序序列!
template <class ForwardIterator, class T> bool binary_search(ForwardIterator first, ForwardIterator last, const T& val) { first = std::lower_bound(first, last, val); return (first != last && !(val < *first>)); }
lower_bound: 在不影響緣由順序的前提下,找到能夠插入的第一個位置。例如序列{10, 10, 10, 20, 20, 20, 30, 30, 30}
,如今須要插入20
,則lower_bound返回指向第一個20的位置。同理,upper_bound指向最後一個20的後面。
template <class ForwardIterator, class T> ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& val) { ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = distance(first, last); while(count>0) { it = first; step = count/2; advance(it, step); if(*it < val)//或者能夠是 if(comp (*it, val)) { first = ++it; count -= step + 1; } else count = step; } return first; }