C++ STL(第二十二篇:算法-- 單純的數據處理算法)

1、概述

前面整理了 STL 最重要的 排序算法,以及 有序區間算法,還有copy、及簡單的算術算法等。但是 STL 還有一些單純的數據處理算法,接下來兩節會對這部分內容進行整理。部分算法比較簡單,就不整理代碼了,只做一個簡單的介紹。

2、數據處理算法

adjacent_find:找出第一組滿足條件的相鄰元素。默認條件是“兩元素相等”,可傳入自定義二元仿函數。

count:統計在 [first, last) 區間內的每一個與指定值相等的元素個數。

count_if:跟上面一樣的功能,只不過傳入一個仿函數,來判斷是否跟傳入值相等。

find: 根據 equallity 操作符,在 [first, last) 區間內,找出第一個匹配 “等同條件” 者。

find_if:跟上面的功能一樣,只不過 equality 操作符,改成傳入一個仿函數。

find_end:在序列一 [first1, last1) 所涵蓋的區間中,查找序列二 [first2, last2) 的最後一次出現點。如果序列一之內不存在“完全匹配序列二”的子序列,便返回迭代器 last1。

find_first_of:以 [first2, last2) 區間內的某些元素作爲查找目標,尋找他們在 [first1, last1) 區間內的第一次出現地點。比如:第二序列爲 aeiou,第一序列爲 synesthesia,則返回第一個 e。底層就是兩層嵌套循環。

for_each:將仿函數 f 施行於 [first, last) 區間內的每一個元素身上。 f 不可改變元素內容,如果想更改,使用transform。

generate:將仿函數 gen 的運算結果填寫在 [first, last) 區間內的所有元素身上。所謂填寫,用的是迭代器所指元素的 assignment 操作符。代碼如下:

template<class ForwardIterator, clas Generator>
void generate(ForwardIterator first, ForwardIterator last, Generator gen)
{
	for( ; first != last; ++first)
		*first = gen();
}

generate_n:將仿函數 gen 的運算結果填寫在從迭代器 first 開始的 n 個元素身上。

max_element:返回一個迭代器,指向序列中數值最大的元素。比較方法可通過仿函數傳入。

min_element:和max_element 相反,返回的迭代器,指向序列中數值最小的元素。

replace:將 [first, last) 區間內的所有 old_value 都以 new_value 取代。

replace_copy:與 replace 類似,唯一不同的是新序列會被複制到 result 所指的容器中。

replace_if:將 [first, last) 區間內所有 被仿函數 pred 評估爲 true 的元素,都以new_value 取代。

replace_copy_if:行爲與 replace_if 類似,但是新序列會被複制到 result 所指區間內。

partition:paritition 會將區間 [first, last) 中的元素重新排列。所有被一元條件運算判定爲true 的元素,都會被放在區間的前端,被判定爲 false 的元素,都會被放在區間後段。這個算法並不保留元素的原始相對位置。如果需要保留,使用 stable_partition。這個算法非常的重要,前面介紹的 partition_sort 和 Quick_sort 都是用的這個思想,而且一堆數據中取第 K大的數也可以用類似的算法。代碼如下:

//所有被 pred 判定爲 true 的元素,都被放到前段
//被 pred 判定爲 false 的元素,都被放到後段,不保證保留元素的相對位置。
template<class BidirectionalIterator, class Predicate>
BidirectionalIterator partition(BidirectionalIterator first, BidirectionalIterator last, Predicate pred)
{
	while(true)
	{
		while(true)
		{
			if( first == last )		//頭指針等於尾指針
				return first;		//所有操作結束
			else if( pred(*first))	//頭指針所指的元素符合不移動條件
				++first;			//說明元素放置是對的,檢查後面的元素,直到第一個不符合條件
			else
				break;
		}
		--last;						//尾指針回溯
		while( true )
		{
			if( first == last )		//頭指針等於尾指針
				return first;
			else if( !pred(*last))
				--last;				//說明元素放置是對的,檢查前面的元素,直到第一個不符合條件
			else
				break;
		}
		iter_swap(first, last);		//交換頭節點 和 尾節點 互不滿足條件的元素,然後進行向下遍歷
		++first;
	}
}

在這裏插入圖片描述
remove:移除(但不刪除)[first,last) 中所有與 value 相等的元素。將每一個不與 value 相等的元素輪番賦值給 first 之後的空間。返回值 ForwardIterator 標示出重新整理後的最後元素的下一個位置。

template<class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value)
{
	first = find(first, last, value);	//查找出第一個相等元素
	ForwardIterator next = first;		//以 next 標示出來
	//利用 “remove_copy() 允許新舊容器重疊 ”  的性質,進行移除操作
	return first == last ? first : remove_copy(++next, last, first, value);
}

remove_copy:移除 [first, last) 區間內所有與 value 相等的元素。而將結果複製到一個以 result 標示起始位置的容器身上。

template<class InputIterator, class OutputIterator, class T>
OutputIterator remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value)
{
	for(; first != last; ++first)
	{
		if( *first != value)
			*result++ = *first;
	}
	return result;
}

remove_if:和前面的 remove 操作差不多,就是 等於操作 改爲 傳入仿函數pred,pred判定爲true 的元素,刪除掉。

remove_copy_if:和 remove_copy 差不多,就是 等於操作 改爲 傳入仿函數pred,pred判定爲true 的元素,刪除掉。

reverse:將序列 [first, last) 的元素在原容器中顛倒重排。迭代器的雙向或隨機定位能力,決定了這個算法的效率。代碼如下:

template<class BidirectionalIterator>
inline void reverse( BidirectionalIterator first,  BidirectionalIterator last)
{
	__reverse(first, last, iterator_category(first));
}

//reverse  的雙向迭代器版本
template<class BidirectionalIterator>
void __reverse( BidirectionalIterator first,  BidirectionalIterator last, bidirectional_iterator_tag)
{
	while( true)
	{
		if( first == last || first == --last)
			return;
		else
			iter_swap(first++,last);
	}
}

//reverse 的隨機地址訪問迭代器的版本
template<class RandomAccessIterator>
void __reverse(RandomAccessIterator first,  RandomAccessIterator last, random_access_iterator_tag)
{
	//頭尾兩兩互換,然後頭部累進一個位置,尾部累退一個位置,兩者交錯時停止
	while( first < last )
	{
		iter_swap(first++,--last);
	}
}

reverse_copy:行爲類似 reverse(),但產生出來的新序列會被置於以 result 指出的容器中。返回值 OutputIterator 指向新產生的最後元素的下一位置。

swap_ranges:將 [first, last) 區間內的元素與 “從 first2 開始、個數相同”的元素互相交換。如果第二序列的長度小於第一序列,或者兩序列在同一容器中且彼此重疊,執行結果未可預期。

transform: transform() 的第一版本以仿函數 op 作用於 [first, last) 中的每一個元素身上,並以其結果產生出一個新序列。第二版本以仿函數 binary_op 作用於一雙元素身上,並以其結果產生出一個新序列。兩個版本都把執行結果放在迭代器 result 所標示的容器中。

template<class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform( InputIterator first, InputIterator last, OutputIterator result, UnaryOperatio op)
{
	for( ;first != last; ++first)
		*result = op(*first);
	return result;
}

template<class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>
OutputIterator transform(InputIterator1 first1, 
							InputIterator1 last1, 
							InputIterator2 first2, 
							InputIterator2 last2, 
							OutputIterator result, 
							BinaryOperation binary_op)
{
	for( ; first1 != last1; ++first1, ++first2, ++result)
		*result = binary_op(*first1, *first2);
	return result;
}

還有一部分,下一節給整理完。

感謝大家,我是假裝很努力的YoungYangD(小羊)。

參考資料:
《STL源碼剖析》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章