STL源碼剖析筆記 —— 第六章

  1. 將無效的迭代器傳給某個算法,雖然是一種錯誤,卻不能保證能夠在編譯時期就被捕獲出來,因爲所謂“迭代器類型”並不是真實的型別,它們只是function template的一種性別參數
  2. 對於所有的數值(numeric)算法,包括adjacent_difference(),accumulate(),inner_product(),partial_sum()等等,均需要包含頭文件< numeric >
  3. 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
    
  4. 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;
    }
    
  5. 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)
    {
    }
    
  6. fill
    將[first,last)內的所有元素改填新值
    template<class ForwardIteraor,class T>
    void fill(ForwardIteraor first,ForwardIteraor last,const T& value)
    {
    }
    
  7. fill_n
    將[first,last)內的前n個元素改填新值,返回的迭代器指向被填入的最後一個元素的下一個位置;如果n超過了容器的大小,則會產生不可預料的後果
    template<class OutputIerator,class Size,class T>
    OutputIterator fill_n(OutputIteratorfirst,Size n,const T& value)
    {
    }
    
  8. mismatch
    用來比較兩個序列,指出兩者之間的第一個不匹配點。返回一對迭代器,分別指向兩序列中的不匹配點。如果第二個序列比第一個序列元素多,則產生不可預計的後果
    在這裏插入圖片描述
    template<class InputIterator1,class InputIterator2>
    pair<InputIterator1,InputIterator2> mismatch(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2)
    {
    }
    
  9. copy
    將輸入區間 [first,last)內的元素拷貝到[result,result+(last-first))內,返回一個迭代器result+(last-first)
    //特殊版本1
    inline char* copy(const char* first,const char* last,char* result)
    {
    	memmove(result,first,last-first);
    	return result+(last-first);
    }
    
    copy()調用_copy_dispatch()有一個泛化版本和兩個偏特化版本(針對T* 和const T*),泛化版本調用_copy(),_copy()根據迭代器類型不同有不同版本,如果迭代器是input類型,則判斷 first == fast 作爲終止拷貝的條件;如果迭代器是random,以(last-first==0)作爲終止拷貝的條件,對於兩個偏特化版本來說,要先判斷類型有無不重要的賦值操作符,如果有不重要的則直接調用memmove(),如果沒有不重要的,則調用迭代器類型爲random的_copy()函數
  10. copy_backward
    實現的技巧與copy()類似,將 [first,last)區間內的每一個元素,以逆行的方向複製到result-1爲起點,方向亦爲逆行的區間上,copy_backward所接受的迭代器必須是BidirectionalIterators
    注:對於copy(), copy_backward(),如果複製的目標區域在輸入區域內的,如果採用memmove拷貝的,不會發生錯誤,否則可能會發生錯誤
  11. 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是個穩定的操作
    ……
    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.2 set_intersection,S1和S2的交集,S1和S2及其交集都是以排序區間表示,返回值爲一個迭代器,指向輸出區間的尾端;由於S1和S2內的每個元素都不需唯一,因此,如果某個值在S1出現n次,在S2出現m次,那麼該值在輸出區間中會出現min(n,m)次,並且全部來自S1。set_insersection是個穩定的操作
    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是個穩定的操作
  12. 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)
    {
    }
    	```
    
  13. count_if
    將制定操作(一個仿函數)pred實施於[frist,last)區間內的每個元素身上,並將“造成pred之計算結果爲true”的所有元素的個數返回
  14. find
    運用equalit() 操作符,循序查找[frist,last)區間內的所有元素,找出第一個匹配equality者,如果找到,就返回一個InputIterator指向該元素,否則返回迭代器last
    template<class InputIterator,class T>
    InputIterator find(InputIterator first,InputIterator last,const T& value)
    {
    }
    
  15. find_if
    將制定操作(一個仿函數)pred實施於[frist,last)區間內的每個元素身上,找出第一個“造成pred之計算結果爲true”者,如果找到,就返回一個InputIterator指向該元素,否則返回迭代器last
  16. 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;
    			} 
    			}
    		}
    	}
    	```
    
  17. find_first_of
    本算法以[first2,last2)區間內的某些元素作爲查找目標,尋找它們在[first1,last1)區間內的第一次出現地點。假設我們希望找出字符序列synesthesia的第一個元音,我們可以定義第二個序列爲aeiou。此算法會返回一個ForwardIterator,指向元音序列中任意元素首次出現於第一序列的地點,此例將指向字符序列的第一個e,如果第一序列滅有包含第二序列的任何元素,返回的將是last1.本算法第一個版本利用equality操作符,第二個版本允許用戶自己指定一個二元運算pred
  18. includes(應用於有序區間)
    判斷序列二S2是否涵蓋於序列一S1,S1和S2都必須是有序序列,其中的元素都可重複,所謂涵蓋即S2內出現的元素S1內都有。如果兩個集合是以less排序includes()也必須以less爲比較函數(這也是includes的缺省狀態)如果兩個集合是以greater排序includes()也必須以greater爲比較函數
  19. 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
    }
    
  20. replace
    template<class ForwardIterator,class T>
    void replace(ForwardIterator first,ForwardIterator last,class T& old_value,class T& new_value)
    {
    	
    }
    
  21. replace_copy
    返回值OutputIterator指向被複制的最後一個元素的下一位置
  22. reverse
    分爲雙向迭代器和隨機迭代器,只有隨機迭代器才能first<last,雙向迭代器只能first==last
  23. rotate
    將[frist,middle)內的元素和[middle,last)內的元素互換
    reverse(first,middle);
    reverse(middle,last);
    reverse(first,last);
    在這裏插入圖片描述
  24. search
    在序列一[frist1,last1)所涵蓋的區間中,查找序列二[frist2,last2)的首次出現點。如果序列一之內不存在“完全匹配序列二”的子序列,便返回迭代器last1。
    	template<class ForwardIterator1,class ForwardIterator2class Distance1class 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;
    	}
    
  25. 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>());
  26. 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;
    	}
    
  27. 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;
    	}
    
  28. upper_bound(應用於有序區間)
    其返回值是“在不破壞排序狀態的原則下,可插入value的最後一個位置”
  29. 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;
    		}
    		}
    	}
    
  30. prev_permutation
    首先,從最尾端開始往前尋找兩個相鄰元素,令第一元素爲* i,第二元素爲* ii,且滿足* i> * ii。找到這一組相鄰元素後,再從最尾端開始往前檢驗,找出第一個小於* i的元素,令爲* j,將i,j對調,再將ii之後的所有元素顛倒排列
  31. partial_sort
    本算法接受一個middle迭代器(位於[first,last)之內),然後重新安排,使序列中的middle-first個最小元素以遞增順序排序,置於[first,middle)內,其餘last-middle個元素安置於[middle,last)中,不保證有任何特定順序。前middle-first個元素利用一個大根堆維護,之後再用sort排序
    在這裏插入圖片描述
  32. sort
    數據量大時,採用快排,分段遞歸排序。一旦分段後的數據量小於某個門檻,就改用插入排序。如果遞歸層次太深,還會改用heap sort。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章