- 將無效的迭代器傳給某個算法,雖然是一種錯誤,卻不能保證能夠在編譯時期就被捕獲出來,因爲所謂“迭代器類型”並不是真實的型別,它們只是function template的一種性別參數
- 對於所有的數值(numeric)算法,包括adjacent_difference(),accumulate(),inner_product(),partial_sum()等等,均需要包含頭文件< numeric >
- accumulate
template<class InputIterator,class T> T accumulate(InputIterator first,InputIterator last,T init) { for(;first!=last;++first) { init=init+*first; } 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; } vector<int>v{1,2,3,4,5}; cout<<accumulate(v.begin(),v.end(),0,minus<int>())<<endl; //-15,0-1-2-3-4-5
- inner_product
template<class InputIterator1,class InputIterator2,class T> T inner_product(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2,T init) { for(;first1!=last1;++first1,++first2) { init=init+(*first1 * *first2); //兩個序列的一般內積 } return init; }
- equal()
如果兩個序列在[first,last)區間內相等,equal()返回true,如果第二個序列的元素比較多,多出來的元素不予考慮。因此,如果我們希望保證兩個序列完全相等,必須先判斷其元素個數是否相同;如果第二個序列的元素比第一個少,則會造成不可預測的結果template<class InputIterator1,class InputIterator2> inline bool euqal(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2) { } template<class InputIterator1,class InputIterator2,class BinaryOperation> inline bool euqal(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2,BinaryOperation binary_op) { }
- fill
將[first,last)內的所有元素改填新值template<class ForwardIteraor,class T> void fill(ForwardIteraor first,ForwardIteraor last,const T& value) { }
- fill_n
將[first,last)內的前n個元素改填新值,返回的迭代器指向被填入的最後一個元素的下一個位置;如果n超過了容器的大小,則會產生不可預料的後果template<class OutputIerator,class Size,class T> OutputIterator fill_n(OutputIteratorfirst,Size n,const T& value) { }
- mismatch
用來比較兩個序列,指出兩者之間的第一個不匹配點。返回一對迭代器,分別指向兩序列中的不匹配點。如果第二個序列比第一個序列元素多,則產生不可預計的後果
template<class InputIterator1,class InputIterator2> pair<InputIterator1,InputIterator2> mismatch(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2) { }
- copy
將輸入區間 [first,last)內的元素拷貝到[result,result+(last-first))內,返回一個迭代器result+(last-first)
copy()調用_copy_dispatch()有一個泛化版本和兩個偏特化版本(針對T* 和const T*),泛化版本調用_copy(),_copy()根據迭代器類型不同有不同版本,如果迭代器是input類型,則判斷 first == fast 作爲終止拷貝的條件;如果迭代器是random,以(last-first==0)作爲終止拷貝的條件,對於兩個偏特化版本來說,要先判斷類型有無不重要的賦值操作符,如果有不重要的則直接調用memmove(),如果沒有不重要的,則調用迭代器類型爲random的_copy()函數//特殊版本1 inline char* copy(const char* first,const char* last,char* result) { memmove(result,first,last-first); return result+(last-first); }
- copy_backward
實現的技巧與copy()類似,將 [first,last)區間內的每一個元素,以逆行的方向複製到result-1爲起點,方向亦爲逆行的區間上,copy_backward所接受的迭代器必須是BidirectionalIterators
注:對於copy(), copy_backward(),如果複製的目標區域在輸入區域內的,如果採用memmove拷貝的,不會發生錯誤,否則可能會發生錯誤 - set/multiset的算法,對於hash_set不適用
11.1 set_union,S1和S2的並集,此集合包含S1和S2內的每一個元素,S1和S2及其並集都是以排序區間表示,返回值爲一個迭代器,指向輸出區間的尾端;由於S1和S2內的每個元素都不需唯一,因此,如果某個值在S1出現n次,在S2出現m次,那麼該值在輸出區間中會出現max(n,m)次,其中n個來自S1,其餘來自S2 。set_union是個穩定的操作
11.2 set_intersection,S1和S2的交集,S1和S2及其交集都是以排序區間表示,返回值爲一個迭代器,指向輸出區間的尾端;由於S1和S2內的每個元素都不需唯一,因此,如果某個值在S1出現n次,在S2出現m次,那麼該值在輸出區間中會出現min(n,m)次,並且全部來自S1。set_insersection是個穩定的操作…… return copy(first2,last2,copy(first1,last1,result)); multiset<int> s1{ 1,2,3,4,5 }; multiset<int> s2{ 1,1,2,2,5,6,7,8,9 }; vector<int> s3; set_union(s1.begin(), s1.end(), s2.begin(), s2.end(),inserter(s3,s3.begin()));
11.3 set_difference,S1和S2的差集,S1-S2,S1和S2及其交集都是以排序區間表示,返回值爲一個迭代器,指向輸出區間的尾端;由於S1和S2內的每個元素都不需唯一,因此,如果某個值在S1出現n次,在S2出現m次,那麼該值在輸出區間中會出現max(n-m,0)次,並且全部來自S1。set_difference是個穩定的操作
11.4 set_symmetric_difference,S1和S2的對稱差集,(S1-S2)並(S2-S1),S1和S2及其對稱差集都是以排序區間表示,返回值爲一個迭代器,指向輸出區間的尾端;由於S1和S2內的每個元素都不需唯一,因此,如果某個值在S1出現n次,在S2出現m次,那麼該值在輸出區間中會出現|n-m|次。set_difference是個穩定的操作 - count
運用equalit() 操作符,將[frist,last)區間內的每個元素和制定value比較,並返回與value相等的元素個數template<class InputIterator,class T> typename iterator_traits<InputIterator>::difference_type count(InputIterator first,InputIterator last,const T& value) { } ```
- count_if
將制定操作(一個仿函數)pred實施於[frist,last)區間內的每個元素身上,並將“造成pred之計算結果爲true”的所有元素的個數返回 - find
運用equalit() 操作符,循序查找[frist,last)區間內的所有元素,找出第一個匹配equality者,如果找到,就返回一個InputIterator指向該元素,否則返回迭代器lasttemplate<class InputIterator,class T> InputIterator find(InputIterator first,InputIterator last,const T& value) { }
- find_if
將制定操作(一個仿函數)pred實施於[frist,last)區間內的每個元素身上,找出第一個“造成pred之計算結果爲true”者,如果找到,就返回一個InputIterator指向該元素,否則返回迭代器last - find_end
在序列一[frist1,last1)所涵蓋的區間中,查找序列二[frist2,last2)的最後一次出現點。如果序列一之內不存在“完全匹配序列二”的子序列,便返回迭代器last1。此函數有兩個版本,版本一使用元素型別所提供的equality操作符,版本二允許用戶指定某個二元運算(以仿函數呈現)作爲判斷元素是否相等的依據
由於這個算法查找的是最後一個出現地點,如果我們有能力逆向查找,題目就變成了“首次出現地點”,逆向查找的關鍵在於迭代器的雙向移動能力,因此,SGI將算法設計爲雙層架構,一般稱呼此種上層函數爲dispatch function(分派函數/派送函數)
這是一種常見的技巧,令函數傳遞調用過程中產生迭代器類型的臨時對象,再利用編譯器的參數推導機制,自動調用某個對應函數template<class ForwardIterator1,class ForwardIterator2> inline ForwardIterator1 find_end(ForwardIterator1 first1,ForwardIterator1 last1,ForwardIterator2 first2,ForwardIterator2 last2) { typedef typename iterator_traits<ForwardIterator1>::iterator_category category1; typedef typename iterator_traits<ForwardIterator2>::iterator_category category2; //以下根據兩個區間的類屬,調用不同 d 下層函數 return _find_end(first1,end1,first2,end2,category1(),category1()); }
//以下是forward iterator 版本 template<class ForwardIterator1,class ForwardIterator2> ForwardIterator1 _find_end(ForwardIterator1 first1,ForwardIterator1 last1,ForwardIterator2 first2,ForwardIterator2 last2,forward_iterator_tag,forward_iterator_tag) { if(first2==last2) return last1; else { ForwardIterator1 result=last1; while(1) { //以下利用search()查找某個子序列的首次出現點,找不到返回last1 ForwardIterator1 new_reslut=search(first1,last1,first2,last2); if(new_reslut==last1) return result; else { result=new_result; first1=new_result; ++first1; } } } } ```
- find_first_of
本算法以[first2,last2)區間內的某些元素作爲查找目標,尋找它們在[first1,last1)區間內的第一次出現地點。假設我們希望找出字符序列synesthesia的第一個元音,我們可以定義第二個序列爲aeiou。此算法會返回一個ForwardIterator,指向元音序列中任意元素首次出現於第一序列的地點,此例將指向字符序列的第一個e,如果第一序列滅有包含第二序列的任何元素,返回的將是last1.本算法第一個版本利用equality操作符,第二個版本允許用戶自己指定一個二元運算pred - includes(應用於有序區間)
判斷序列二S2是否涵蓋於序列一S1,S1和S2都必須是有序序列,其中的元素都可重複,所謂涵蓋即S2內出現的元素S1內都有。如果兩個集合是以less排序includes()也必須以less爲比較函數(這也是includes的缺省狀態)如果兩個集合是以greater排序includes()也必須以greater爲比較函數 - remove
移除[frist,last)之中所有與value相等的元素,但是並不真正從容器中刪除那些元素template<class ForwardIterator,class T> ForwardIterator remove(ForwardIterator first,ForwardIterator last,const T& value) { first=find(first,last,value); ForwardIterator next=first; return first==last?first:remove_copy(++next,last,first,value); } template<class ForwardIterator,class OutputIterator,class T> OutputIterator remove_copy(ForwardIterator first,ForwardIterator last,OutputIterator result,const T& value) { for(;first!=last;++first) { if(*first!=value) { *result=*first; ++result; } } return result;6 }
- replace
template<class ForwardIterator,class T> void replace(ForwardIterator first,ForwardIterator last,class T& old_value,class T& new_value) { }
- replace_copy
返回值OutputIterator指向被複制的最後一個元素的下一位置 - reverse
分爲雙向迭代器和隨機迭代器,只有隨機迭代器才能first<last,雙向迭代器只能first==last - rotate
將[frist,middle)內的元素和[middle,last)內的元素互換
reverse(first,middle);
reverse(middle,last);
reverse(first,last);
- search
在序列一[frist1,last1)所涵蓋的區間中,查找序列二[frist2,last2)的首次出現點。如果序列一之內不存在“完全匹配序列二”的子序列,便返回迭代器last1。template<class ForwardIterator1,class ForwardIterator2,class Distance1,class Distance2> ForwardIterator1 _search(ForwardIterator1 first1,ForwardIterator1 last1,ForwardIterator2 first2,ForwardIterator2 last2,Distance1*,Distance2*) { Distance1 d1=0; distance(first1,last1,d1); Distance2 d2=0; distance(first2,last2,d2); if(d1<d2) return last1; ForwardIterator1 current1=first1; ForwardIterator2 current2=first2; while(current2!=last2) { if(*current1==*current2) { current1++; current2++; } else { if(d1==d2) return last1; else { current1=++first1; current2=first2; --d1; } } } return first1; }
- search_n
在序列[frist,last)所涵蓋的區間中,查找“連續count個符合條件之元素”所形成的子序列,並返回一個迭代器指向該子序列起始處。如果找不到這樣的子序列,就返回迭代器last,版本一是相等條件,版本二是指用戶指定的某個二元運算(以仿函數呈現)
查找兩個連續的8所形成的子序列的起點,可以這麼寫
iter1=search_n(iv.begin(),iv.end(),2,8);
查找連續三個小於8的元素所形成的子序列的起點,可以這麼寫
iter2=search_n(iv.begin(),iv.end(),3,8,less< int>()); - unique
unique能夠一處重複的元素,每當在[frist,last)內遇到有重複元素羣,它便移除該元素羣中第一個以後的所有元素。注意,unique只移除相鄰的重複元素,如果你想要移除所有(包括不相鄰的)重複元素,必須先將序列排序,使所有重複元素都相鄰。unique會返回一個迭代器指向新區間的尾端,新區間之內不含相鄰的重複元素,這個算法是穩定的。template<class InputIterator,class ForwardIterator> ForwardIterator _unique_copy(InputIterator first,InputIterator last,ForwardIterator result,forward_iterator_tag) { *result=*first; while(++first!=last) { if(*result!=*first) *++result=*first; } return ++result; }
- lower_bound(應用於有序區間)
是二分查找的一種版本,試圖在已排序的[first,last)中尋找value,返回一個迭代器,指向第一個“不下於value”的元素,另一個角度看,其返回值是“在不破壞排序狀態的原則下,可插入value的第一個位置”template<class ForwardIterator ,class T> inline ForwardIterator lower_bound(ForwardIterator first,ForwardIterator last,const T& value) { return _lower_bound(first,last,value,distance_type(first),iterator_category(first)); } template<class ForwardIterator ,class T,class Distance> inline ForwardIterator _lower_bound(ForwardIterator first,ForwardIterator last,const T& value,Distance* ,forward_iterator_tag) { DIstance len=0; distance(first,last,len); Distance half; ForwardIterator middle; while(len>0) { half=len>>1; middle=first; advance(middle,half); if(*middle<value) { first=middle; ++first; len=len-half-1; } else len=half; } return first; }
- upper_bound(應用於有序區間)
其返回值是“在不破壞排序狀態的原則下,可插入value的最後一個位置” - next_permutation
首先,從最尾端開始往前尋找兩個相鄰元素,令第一元素爲* i,第二元素爲* ii,且滿足* i< * ii。找到這一組相鄰元素後,再從最尾端開始往前檢驗,找出第一個大於* i的元素,令爲* j,將i,j對調,再將ii之後的所有元素顛倒排列template<class BidirectionalIterator> bool next_permutation(BidirectionalIterator first,BidirectionalIterator last) { if(first==last) return false; BidirectionalIterator i=first; ++i; if(i==last) return false; --i; for(;;) { BidirectionalIterator ii=i; --i; if(*i<*ii) { BidirectionalIterator j=last; while(*(*i<*--j)); iter_swap(i,j); reverse(ii,last); return true; } if(i==last) { reverse(first,last); return false; } } }
- prev_permutation
首先,從最尾端開始往前尋找兩個相鄰元素,令第一元素爲* i,第二元素爲* ii,且滿足* i> * ii。找到這一組相鄰元素後,再從最尾端開始往前檢驗,找出第一個小於* i的元素,令爲* j,將i,j對調,再將ii之後的所有元素顛倒排列 - partial_sort
本算法接受一個middle迭代器(位於[first,last)之內),然後重新安排,使序列中的middle-first個最小元素以遞增順序排序,置於[first,middle)內,其餘last-middle個元素安置於[middle,last)中,不保證有任何特定順序。前middle-first個元素利用一個大根堆維護,之後再用sort排序
- sort
數據量大時,採用快排,分段遞歸排序。一旦分段後的數據量小於某個門檻,就改用插入排序。如果遞歸層次太深,還會改用heap sort。
STL源碼剖析筆記 —— 第六章
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.