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源碼剖析》