1. STL 算法 STL 算法主要实现在 stl_algo.h、stl_algobase.h、stl_numeric.h 文件中,所有的 STL 算法都是作用在用迭代器 [first, last) 表示的范围上。可以根据算法执行过程中是否会改变给定区间的元素,将算法分为 mutating algorithm 和 nonmutating algorithm。mutating algorithm有诸如 copy、swap、replace、fill、remove、partition等,nonmutating algorithm有诸如find、search、count、for_each、equal、max、min等。
2. STL 算法的一般形式 所有的泛型算法前两个参数都是一对用于表示算法作用范围的迭代器[first, last),迭代器使用前闭后开的区间,这样当 first == last 就可以表示一个空的区间范围,这对迭代器的必要条件就是 first 可以通过累加达到 last,也就是 operator++ 被正确的重载了。许多 STL 算法有多个版本,比如默认的行为、传递一个仿函数等。mutating algorithm 通常会有两个版本,一个是原地地改变操作地对象,另一版本就是将结果保存到指定的容器,而原来的容器不会有任何的变化(copy版总是以 _copy
结尾),比如 replace() 和 replace_copy()。所有地数值(numeric)算法都是实现在 stl_numeric.h 中,其它算法都是是现在 stl_algo.h 和 stl_algobase.h 中。这些文件的顶层文件都是平时写代码要 include 的 。
3. 算法的泛化过程 STL 算法的泛型化目标就是将算法独立于所处理的数据结构之外,不受数据结构的羁绊,使其适用于大多数的数据结构(这些数据结构可能使 array、vector、list、deque)。要实现这个目标,关键在于把操作对象的类型抽象化,同时把操作对象的表示法和移动行为抽象化,那么整个算法就是在一个抽象的层面工作了,这就是算法的泛化。
4. 数值算法 <stl_numeric.h> 数值算法被实现在文件 <stl_numeric.h> 中,要使用数值算法需要 include 文件 。
4.1 accumulate accumulate 计算给定范围的的所有值的和,并且必须提供一个初始值(这是为了当给定范围是空的时候可以返回一个明确的值),可以执行二元操作的类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <typename _InputIterator, typename _Tp> inline _Tp accumulate (_InputIterator __first, _InputIterator __last, _Tp __init) { for (; __first != __last; ++__first) __init = __init + *__first; return __init; } template <typename _InputIterator, typename _Tp, typename _BinaryOperation> inline _Tp accumulate (_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOperation __binary_op) { for (; __first != __last; ++__first) __init = __binary_op(__init, *__first); return __init; }
4.2 adjacent_difference adjacent_difference 计算相邻元素得差值,结果存储在给定的第三个参数 result中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 template <typename _InputIterator, typename _OutputIterator>_OutputIterator adjacent_difference (_InputIterator __first, _InputIterator __last, _OutputIterator __result) { if (__first == __last) return __result; _ValueType __value = *__first; *__result = __value; while (++__first != __last) { _ValueType __tmp = *__first; *++__result = __tmp - __value; __value = _GLIBCXX_MOVE(__tmp); } return ++__result; } template <typename _InputIterator, typename _OutputIterator,typename _BinaryOperation>_OutputIterator adjacent_difference (_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOperation __binary_op) { typedef typename iterator_traits<_InputIterator>::value_type _ValueType; if (__first == __last) return __result; _ValueType __value = *__first; *__result = __value; while (++__first != __last) { _ValueType __tmp = *__first; *++__result = __binary_op(__tmp, __value); __value = _GLIBCXX_MOVE(__tmp); } return ++__result; }
4.3 inner_product inner_product 用来计算两个容器的内积(对应元素之间的操作),为了使的有容器为空时,可以获得一个明确定义的结果,比如要计算两个 vector 的内积,初值提供为0即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <typename _InputIterator1, typename _InputIterator2, typename _Tp>inline _Tp inner_product (_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _Tp __init) { for (; __first1 != __last1; ++__first1, (void )++__first2) __init = __init + (*__first1 * *__first2); return __init; } template <typename _InputIterator1, typename _InputIterator2, typename _Tp,typename _BinaryOperation1, typename _BinaryOperation2>inline _Tp inner_product (_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2) { for (; __first1 != __last1; ++__first1, (void )++__first2) __init = __binary_op1(__init, __binary_op2(*__first1, *__first2)); return __init; }
4.4 partial_sum partial_sum 用于计算局部的和,将 *first
赋值给 *result
,然后将 *first
和 *(first + 1)
的和赋值给 *(result + 1)
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 template <typename _InputIterator, typename _OutputIterator>_OutputIterator partial_sum (_InputIterator __first, _InputIterator __last, _OutputIterator __result) { typedef typename iterator_traits<_InputIterator>::value_type _ValueType; if (__first == __last) return __result; _ValueType __value = *__first; *__result = __value; while (++__first != __last) { __value = __value + *__first; *++__result = __value; } return ++__result; } template <typename _InputIterator, typename _OutputIterator,typename _BinaryOperation>_OutputIterator partial_sum (_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOperation __binary_op) { if (__first == __last) return __result; _ValueType __value = *__first; *__result = __value; while (++__first != __last) { __value = __binary_op(__value, *__first); *++__result = __value; } return ++__result; }
4.5 iota iota 是一个希腊字符的读音(eye-oh-duh),该算法从依次将范围[first, last)的值加上一个 value,而 value 每次都执行 operator++操作。
1 2 3 4 5 6 7 template <typename _ForwardIterator, typename _Tp>void iota (_ForwardIterator __first, _ForwardIterator __last, _Tp __value) { for (; __first != __last; ++__first) { *__first = __value; ++__value; } }
5. 基本算法 <stl_algobase.h> STL算法并没有简单复杂之分,把一些常用的算法实现在 <stl_algobase.h>,其他的算法是现在 <stl_alog.h> 中。
5.1 equal, fill, fill_n, iter_swap, lexicographical_compare, max, min, mismatch, swap 这几个算法的实现都很简单,无非就是顺序遍历给定的迭代器区间,执行对应的操作。
equal equal 用于判断两个容器在区间[first, last)之间是否相等,如果相等则返回 true,如果第二个容器元素比较多,则多出的部分不考虑,也就是说 equal() 是不能用来判断两个容器是否相等的,因为第二个容器多出来的元素没有被考虑。
fill fill() 将所有容器区间[first, last)改为新的值。
fill_n 将[first, first + n)范围内的值改写为新的值,如果超出容器范围会有不可预期的结果,因此可以传入一个有插入功能的迭代器,而不是覆盖的迭代器。
1 2 3 4 5 6 7 int ia[] = { 0 , 1 , 2 };std ::vector <int > ivec(ia, ia + 3 );std ::fill_n(std ::inserter(ivec, ivec.begin()), 5 , 9 );for ( const int num : ivec ) display<int >()(num); std ::cout << std ::
iter_swap iter_swap() 将两个迭代器指向的内容互换。
lexicographical_compare 故名思意就是字典序比较,比较给定区间[first1, last1)和[first2, last2)的对应位置,依次比较会出现三种情况
某一对应元素彼此不相等
两个区间大小相同,同时到达 last1 和 last2;
两个区间大小不同,到达 last1 或者 last2;
返回值:当第一序列小于第二序列返回 true
当某组对应元素不相等,如果第一序列较小,则返回 true,否则返回 false;
当到达了 last1 而没有到达 last2,返回 true;
当没有到达 last2 而到达了 last1,返回 false;
同时到达 last1 和 last2(所有元素都匹配),那么返回 false(因为序列1不小于序列2)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 template <typename _II1, typename _II2, typename _Compare>bool __lexicographical_compare_impl(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2, _Compare __comp) { __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2); for (; __first1 != __last1 && __rai_type::__cnd2(__first2, __last2); ++__first1, (void )++__first2) { if (__comp(__first1, __first2)) return true ; if (__comp(__first2, __first1)) return false ; } return __first1 == __last1 && __first2 != __last2; }
max max() 返回两个对象的大者,有两个版本,一个使用参数对象提供的的 operator< 来判断大者,另一个版本可以传入一个仿函数作为参数判断两个对象的大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 template <typename _Tp>_GLIBCXX14_CONSTEXPR inline const _Tp& max (const _Tp& __a, const _Tp& __b) { if (__a < __b) return __b; return __a; } template <typename _Tp, typename _Compare>inline const _Tp& min (const _Tp& __a, const _Tp& __b, _Compare __comp) { if (__comp(__b, __a)) return __b; return __a; }
min min() 返回两个给定对象中的小者,和 max 类似。
mismatch mismatch() 用来平行比较两个序列,用一个 pair 的形式返回二者之间的第一个不匹配点。
1 2 3 4 5 6 7 8 9 10 11 12 13 template <typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate>pair<_InputIterator1, _InputIterator2> __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __binary_pred) { while (__first1 != __last1 && __first2 != __last2 && __binary_pred(__first1, __first2)) { ++__first1; ++__first2; } return pair<_InputIterator1, _InputIterator2>(__first1, __first2); }
swap swap() 用来交换两个位置的值。5.2 copy copy() 将容器的一个区间的内容拷贝到容器的另一个区间(可以是同一个容器),一般来说拷贝操作无非就是利用 assignment operator 或者 copy constructor,而 copy() 算法使用的就是 operator=。STL的原则就是尽量使用内存直接拷贝,节省时间开销。STL 算法使用了函数重载,类型特性,偏特化等方法加快 copy() 的执行速度。比如,泛化的 copy() 一般来说接受两个迭代器表示拷贝的范围,因此每次要逐一比较两个迭代器是不是相等来盘算是不是已经全部拷贝完了,这种方法是比较慢的。可以使用特化的方法,先算出需要拷贝的元素的数量,然后用一个循环来拷贝,不用多次比较迭代器,速度更快。
1 2 3 4 5 6 7 8 9 10 for ( ; first != last; ) { } for ( ; n < last - first; ) { }
5.3 copy_backward copy_backward() 和 copy() 类似,将[first, last)逆向拷贝到以 result - 1 为起点的区间(方向也是反向,使用反向迭代器实现)。
6. set 相关算法 set 相关算法包括 union、intersection、difference、symmetric difference,实现在 <stl_algo.h>中。
6.1 set_difference set_difference 返回两个有序 区间的差集,差集包含“出现在第一个区间但是不出现在第二个区间的元素”。set_difference 是一种 stable 操作,也就是结果的元素顺序和区间一保持一致。这个算法有两个版本,第一个版本是使用 operator< 进行比较,另一个版本是提供一个仿函数 comp 进行元素的比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 template <typename _InputIterator1, typename _InputIterator2, typename _OutputIterator, typename _Compare> _OutputIterator __set_difference(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { while (__first1 != __last1 && __first2 != __last2) if (__comp(__first1, __first2)) { *__result = *__first1; ++__first1; ++__result; } else if (__comp(__first2, __first1)) ++__first2; else { ++__first1; ++__first2; } return std ::copy(__first1, __last1, __result); }
6.2 set_union set_union() 获得两个排序区间的并集,“并集包含所有出现在第一区间或者第二区间的元素”,返回一个指向结果区间末尾的迭代器。set_union 是一个 stable 操作,两个输入区间的元素都不要求唯一,如果一个元素在第一区间出现 a 次,在第二区间出现 b 次,那么并集中该元素出现次数为 max(a, b)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 template <typename _InputIterator1, typename _InputIterator2,typename _OutputIterator, typename _Compare>_OutputIterator __set_union(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { while (__first1 != __last1 && __first2 != __last2) { if (__comp(__first1, __first2)) { *__result = *__first1; ++__first1; } else if (__comp(__first2, __first1)) { *__result = *__first2; ++__first2; } else { *__result = *__first1; ++__first1; ++__first2; } ++__result; } return std ::copy(__first2, __last2, std ::copy(__first1, __last1, __result)); }
6.3 set_intersection set_intersection 构造两个有序区间的交集,“交集中包含的元素同时出现在一区间和二区间”。set_intersection 的两个输入区间不要求元素唯一,是一种 stable 的操作,同样提供两个版本,一个是operator<,另一个是仿函数用于比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <typename _InputIterator1, typename _InputIterator2,typename _OutputIterator, typename _Compare>_OutputIterator __set_intersection(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { while (__first1 != __last1 && __first2 != __last2) if (__comp(__first1, __first2)) ++__first1; else if (__comp(__first2, __first1)) ++__first2; else { *__result = *__first1; ++__first1; ++__first2; ++__result; } return __result; }
6.4 set_symmetric_difference set_symetric_difference 对称差集,“对称差集包含出现在一区间但不出现在二区间,以及,出现在二区间但不出现在一区间的元素”, 同样不要求两个区间元素唯一,是 stable 操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <typename _InputIterator1, typename _InputIterator2,typename _OutputIterator, typename _Compare>_OutputIterator __set_symmetric_difference(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { while (__first1 != __last1 && __first2 != __last2) if (__comp(__first1, __first2)) { *__result = *__first1; ++__first1; ++__result; } else if (__comp(__first2, __first1)) { *__result = *__first2; ++__first2; ++__result; } else { ++__first1; ++__first2; } return std ::copy(__first2, __last2, std ::copy(__first1, __last1, __result)); }
7. heap 算法 heap 算法在序列式容器中,包含 :push_heap, pop_heap, make_heap, sort_heap算法, <stl_algo.h>包含了文件<stl_heap.>。
8. 其他算法 由于STL算法常常需要传递一个谓词(predicate)或者仿函数(functor),先记录一下这两者的具体区别:
functor:functor 是一个函数对象(Function object),使一个类看上去像一个函数,在实现上是重载 operator() ,functor 就是某个类的实例,行为和函数类似,像调用函数一样使用函数对象。
predicate:谓词是一个判断式,是一个返回 bool 值得函数或者仿函数,几元谓词就表示函数参数得个数。
8.1 find find() 返回给定区间[first, last)中出现的第一个与要查找元素相等的迭代器。find() 调用的是 std::__find_if()
,并提供一个表示相等的谓词(predicate):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <typename _InputIterator, typename _Predicate>inline _InputIterator __find_if(_InputIterator __first, _InputIterator __last, _Predicate __pred, input_iterator_tag) { while (__first != __last && !__pred(__first)) ++__first; return __first; } template <typename _InputIterator, typename _Tp>inline _InputIterator find (_InputIterator __first, _InputIterator __last, const _Tp& __val) { return std ::__find_if(__first, __last, __gnu_cxx::__ops::__iter_equals_val(__val)); }
8.2 find_if find_if() 返回给定区间中第一个使得给定谓词(predicate)为 true 的元素的迭代器,否则返回 end()。
1 2 3 4 5 template <typename _InputIterator, typename _Predicate>inline _InputIterator find_if (_InputIterator __first, _InputIterator __last, _Predicate __pred) { return std ::__find_if(__first, __last, __gnu_cxx::__ops::__pred_iter(__pred)); }
8.3 find_first_of find_first_of() returns an iterator to the first element in the range [first1, last1) that matches any of the elements in [first2, last2). If no such element is found, the function returns last1 . The elements in [first1, last1) ared sequentially compared to each of the values in [first2, last2) using operator==(or predicate in version 2), until a pair matches.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <typename _InputIterator, typename _ForwardIterator>_InputIterator find_first_of (_InputIterator __first1, _InputIterator __last1, _ForwardIterator __first2, _ForwardIterator __last2) { for (; __first1 != __last1; ++__first1) for (_ForwardIterator __iter = __first2; __iter != __last2; ++__iter) if (*__first1 == *__iter) return __first1; return __last1; } template <typename _InputIterator, typename _ForwardIterator, typename _BinaryPredicate>_InputIterator find_first_of (_InputIterator __first1, _InputIterator __last1, _ForwardIterator __first2, _ForwardIterator __last2, _BinaryPredicate __comp) { for (; __first1 != __last1; ++__first1) for (_ForwardIterator __iter = __first2; __iter != __last2; ++__iter) if (__comp(*__first1, *__iter)) return __first1; return __last1; }
8.4 find_end find_end() 返回区间二在区间一出现的最后一个位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <typename _ForwardIterator1, typename _ForwardIterator2,typename _BinaryPredicate>_ForwardIterator1 __find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2, forward_iterator_tag, forward_iterator_tag, _BinaryPredicate __comp) { if (__first2 == __last2) return __last1; _ForwardIterator1 __result = __last1; while (1 ) { _ForwardIterator1 __new_result = std ::__search(__first1, __last1, __first2, __last2, __comp); if (__new_result == __last1) return __result; else { __result = __new_result; __first1 = __new_result; ++__first1; } } }
8.5 adjacent_find Searches the range [first, last) for the first occurence of two consecutive elements that match, and return an iterator to the first of these two elements, or last if no such found. There are two versions of the function, one is compares equal using opeartor==, the other using pred.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <typename _ForwardIterator, typename _BinaryPredicate>_ForwardIterator __adjacent_find(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __binary_pred) { if (__first == __last) return __last; _ForwardIterator __next = __first; while (++__next != __last) { if (__binary_pred(__first, __next)) return __first; __first = __next; } return __last; } template <typename _ForwardIterator>inline _ForwardIteratoradjacent_find(_ForwardIterator __first, _ForwardIterator __last) { return std ::__adjacent_find(__first, __last, __gnu_cxx::__ops::__iter_equal_to_iter()); } template <typename _ForwardIterator, typename _BinaryPredicate>inline _ForwardIterator adjacent_find (_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __binary_pred) { return std ::__adjacent_find(__first, __last, __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); }
8.6 count count() returns the number of elements in the range [first, last) that compare equal to val. The function uses operator== to compare the individual elements to val.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <typename _InputIterator, typename _Tp>inline typename iterator_traits<_InputIterator>::difference_type count(_InputIterator __first, _InputIterator __last, const _Tp& __value) { return std ::__count_if(__first, __last, __gnu_cxx::__ops::__iter_equals_val(__value)); } template <typename _InputIterator, typename _Predicate>typename iterator_traits<_InputIterator>::difference_type __count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) { for (; __first != __last; ++__first) if (__pred(__first)) ++__n; return __n; }
8.7 count_if count_if() returns the number of elements in the range [first, last) for which pred is true.
1 2 3 4 5 6 template <typename _InputIterator, typename _Predicate>inline typename iterator_traits<_InputIterator>::difference_typecount_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) { return std ::__count_if(__first, __last, __gnu_cxx::__ops::__pred_iter(__pred)); }
8.8 search 在区间一[first1, last1)中查找区间二[first2, last2)的首次出现的位置,如果找不到则返回 last1。 // 会不会使用KMP算法呢?为什么不适用KMP算法?可能的原因:
大部分出现的都是比较短的容器的匹配(短字符串),普通的算法已经表现足够用了。而KMP需要初始分配内存,需要预计算(生成偏移量表),这些都可能影响性能,导致在比较短的对象的情况下表现不如暴力法,而大数据量可能会需要更加专门的数据结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 template <typename _ForwardIterator1, typename _ForwardIterator2,typename _BinaryPredicate>_ForwardIterator1 __search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2, _BinaryPredicate __predicate) { if (__first1 == __last1 || __first2 == __last2) return __first1; _ForwardIterator2 __p1(__first2); if (++__p1 == __last2) return std ::__find_if(__first1, __last1, __gnu_cxx::__ops::__iter_comp_iter(__predicate, __first2)); _ForwardIterator2 __p; _ForwardIterator1 __current = __first1; for (;;) { __first1 = std ::__find_if(__first1, __last1, __gnu_cxx::__ops::__iter_comp_iter(__predicate, __first2)); if (__first1 == __last1) return __last1; __p = __p1; __current = __first1; if (++__current == __last1) return __last1; while (__predicate(__current, __p)) { if (++__p == __last2) return __first1; if (++__current == __last1) return __last1; } ++__first1; } \eturn __first1; }
8.9 for_each for_each() 对给定区间的元素执行给定操作,给定的操作必须不能改变元素,因为 for_each() 参数是 inputIterator,不保证接受赋值行为,仿函数f的返回值被忽略,返回值是给定的仿函数f(函数对象)。
1 2 3 4 5 6 template <typename _InputIterator, typename _Function>_Function for_each (_InputIterator __first, _InputIterator __last, _Function __f) { for (; __first != __last; ++__first) __f(*__first); return __f; }
8.10 generate generate() 将仿函数 gen 的执行结果写到给定区间的所有元素,所谓写,用的是元素的 assignment 操作符。
1 2 3 4 5 6 template <typename _ForwardIterator, typename _Generator>void generate (_ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { for (; __first != __last; ++__first) *__first = __gen(); }
8.11 generate_n generate_n() 和 generate() 类似,但是仅仅将 gen 的执行结果填写从给定迭代器起的 n 个元素,如果容器范围不够,结果不可预测。
8.12 includes(应用于有序区间) 两个有序区间,判断区间二是否是区间一的子序列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 template <typename _InputIterator1, typename _InputIterator2>inline bool includes (_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { return std ::__includes(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_less_iter()); } template <typename _InputIterator1, typename _InputIterator2, typename _Compare> inline bool includes (_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Compare __comp) { return std ::__includes(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_comp_iter(__comp)); } template <typename _InputIterator1, typename _InputIterator2,typename _Compare>bool __includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Compare __comp) { while (__first1 != __last1 && __first2 != __last2) if (__comp(__first2, __first1)) return false ; else if (__comp(__first1, __first2)) ++__first1; else { ++__first1; ++__first2; } return __first2 == __last2; }
8.13 max_element max_element() 返回给定区间的最大值的迭代器,区间为空返回 first。max() 函数可以直接调用 max_element() 函数,获得迭代器后解引用即可。
1 2 3 4 5 6 7 8 9 10 11 12 template <typename _ForwardIterator, typename _Compare>_GLIBCXX14_CONSTEXPR _ForwardIterator __max_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { if (__first == __last) return __first; _ForwardIterator __result = __first; while (++__first != __last) if (__comp(__result, __first)) __result = __first; return __result; }
8.14 min_element min_element() 和 max_element() 类似。
8.15 merge merge() 将两个有序 区间 merge 为 一个有序区间,输出到指定的结果容器。算法版本1使用 operator< 比较元素,版本2可以传递一个仿函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <typename _InputIterator1, typename _InputIterator2,typename _OutputIterator, typename _Compare>_OutputIterator __merge(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { while (__first1 != __last1 && __first2 != __last2) { if (__comp(__first2, __first1)) { *__result = *__first2; ++__first2; } else { *__result = *__first1; ++__first1; } ++__result; } return std ::copy(__first2, __last2, std ::copy(__first1, __last1, __result)); }
8.16 partition partition() 将给定区间[first, last)的元素根据给定的一元运算条件 pred 判定为 true 或者 false 分为两部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 template <typename _ForwardIterator, typename _Predicate>_ForwardIterator __partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag) { if (__first == __last) return __first; while (__pred(*__first)) if (++__first == __last) return __first; _ForwardIterator __next = __first; while (++__next != __last) if (__pred(*__next)) { std ::iter_swap(__first, __next); ++__first; } return __first; } template <typename _BidirectionalIterator, typename _Predicate>_BidirectionalIterator __partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred, bidirectional_iterator_tag) { 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 (!bool (__pred(*__last))) --__last; else break ; std ::iter_swap(__first, __last); ++__first; } }
8.17 remove 移除但是不删除 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <typename _ForwardIterator, typename _Predicate>_ForwardIterator __remove_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { __first = std ::__find_if(__first, __last, __pred); if (__first == __last) return __first; _ForwardIterator __result = __first; ++__first; for (; __first != __last; ++__first) if (!__pred(__first)) { *__result = _GLIBCXX_MOVE(*__first); ++__result; } return __result; } template <typename _ForwardIterator, typename _Tp>inline _ForwardIterator remove(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { return std ::__remove_if(__first, __last, __gnu_cxx::__ops::__iter_equals_val(__value)); }
8.18 remove_copy remove_copy() 移除给定区间内所有和给定值相等的元素,但是不是从给定的区间中移除,也就是给定区间不会有任何的变化,而是将结果故知道一个 result 的容器中,如果 result 的大小不足以容纳结果,那么会产生无法预期的结果(不知道复制到哪里去了),返回值是指向被拷贝的元素的最后一个元素的下一个位置。remove_copy() 是 stable 的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <typename _InputIterator, typename _OutputIterator, typename _Tp>inline _OutputIterator remove_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, const _Tp& __value) { return std ::__remove_copy_if(__first, __last, __result, __gnu_cxx::__ops::__iter_equals_val(__value)); } template <typename _InputIterator, typename _OutputIterator,typename _Predicate>_OutputIterator __remove_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred) { for (; __first != __last; ++__first) if (!__pred(__first)) { *__result = *__first; ++__result; } return __result; }
8.19 remove_if remove_if() 移除给定区间的所有使得 functor pred 为 true 的元素,但是并不是真正移除元素,而是将所有使得 pred 为 false 的元素一个一个赋值给 first 之后的位置。返回最后一个 false 的元素的下一个位置。由于原来的容器还有残留数据,因此如果要清除这些数据可以使用容器的成员函数 erase() 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <typename _ForwardIterator, typename _Predicate>inline _ForwardIterator remove_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { return std ::__remove_if(__first, __last, __gnu_cxx::__ops::__pred_iter(__pred)); } template <typename _ForwardIterator, typename _Predicate>_ForwardIterator __remove_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { __first = std ::__find_if(__first, __last, __pred); if (__first == __last) return __first; _ForwardIterator __result = __first; ++__first; for (; __first != __last; ++__first) if (!__pred(__first)) { *__result = _GLIBCXX_MOVE(*__first); ++__result; } return __result;}
8.20 remove_copy_if remove_copy_if() 将给定区间的所有使得仿函数 pred 判定为 true 的元素,但是不是真正删除元素,而是将判定为 false 的元素拷贝到一个以 result 为起始位置的容器中。新的结果容器可以和旧的容器重叠。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <typename _InputIterator, typename _OutputIterator, typename _Predicate> inline _OutputIteratorremove_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred) { return std ::__remove_copy_if(__first, __last, __result, __gnu_cxx::__ops::__pred_iter(__pred)); } template <typename _InputIterator, typename _OutputIterator, typename _Predicate> _OutputIterator __remove_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred) { for (; __first != __last; ++__first) if (!__pred(__first)) { *__result = *__first; ++__result; } return __result; }
8.21 replace replace() 将给定区间的所有 old_value 替换为 new_value。
1 2 3 4 5 6 7 template <typename _ForwardIterator, typename _Tp>void replace (_ForwardIterator __first, _ForwardIterator __last, const _Tp& __old_value, const _Tp& __new_value) { for (; __first != __last; ++__first) if (*__first == __old_value) *__first = __new_value; }
8.22 replace_copy replace_copy() 作用和 replace() 类似,但是原来的容器不会被改变,而是将结果拷贝到给定的容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 template <typename _InputIterator, typename _OutputIterator, typename _Tp>inline _OutputIteratorreplace_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, const _Tp& __old_value, const _Tp& __new_value) { return std ::__replace_copy_if(__first, __last, __result, __gnu_cxx::__ops::__iter_equals_val(__old_value), __new_value); } template <typename _InputIterator, typename _OutputIterator,typename _Predicate, typename _Tp>_OutputIterator __replace_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred, const _Tp& __new_value) { for (; __first != __last; ++__first, (void )++__result) if (__pred(__first)) *__result = __new_value; else *__result = *__first; return __result; }
8.23 replace_if replace_if() 将给定区间的所有使得仿函数 pred 为 true 的元素赋值为新值。
1 2 3 4 5 6 7 8 template <typename _ForwardIterator, typename _Predicate, typename _Tp>void replace_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, const _Tp& __new_value) { for (; __first != __last; ++__first) if (__pred(*__first)) *__first = __new_value; }
8.24 replace_copy_if replace_copy_if() 和 replace_if 类似,但是结果将会被写到给定的一个 result 为起始位置的容器,而原来的容器不会由任何的变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 template <typename _InputIterator, typename _OutputIterator,typename _Predicate, typename _Tp>_OutputIterator __replace_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred, const _Tp& __new_value) { for (; __first != __last; ++__first, (void )++__result) if (__pred(__first)) *__result = __new_value; else *__result = *__first; return __result; }
8.25 reverse reverse() 将给定的区间的元素颠倒重排。根据传递的不同的迭代器类型(比如 vector 和 list 就是不同的迭代器类型),很多 STL 算法都是这个实现的套路的,reverse() 调用不同的实现的版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 template <typename _BidirectionalIterator>inline void reverse(_BidirectionalIterator __first, _BidirectionalIterator __last) { std ::__reverse(__first, __last, std ::__iterator_category(__first)); } template <typename _BidirectionalIterator>void __reverse(_BidirectionalIterator __first, _BidirectionalIterator __last, bidirectional_iterator_tag) { while (true ) if (__first == __last || __first == --__last) return ; else { std ::iter_swap(__first, __last); ++__first; } } template <typename _RandomAccessIterator>void __reverse(_RandomAccessIterator __first, _RandomAccessIterator __last, random_access_iterator_tag) { if (__first == __last) return ; --__last; while (__first < __last) { std ::iter_swap(__first, __last); ++__first; --__last; } }
8.26 reverse_copy 行为类似于上一个函数 reverse,只不过是不改变原来的序列,而是将结果写到一个以 result 为起始位置的容器中。
1 2 3 4 5 6 7 8 9 10 11 12 template <typename _BidirectionalIterator, typename _OutputIterator>_OutputIterator reverse_copy(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) { while (__first != __last) { --__last; *__result = *__last; ++__result; } return __result; }
8.27 rotate rotate() 将区间 [first, middle) 的元素和区间 [middle, last) 的元素互换,middle 所指向的元素将会称为第0个元素,比如区间{ 9, 8, 7, 6, 5, 4, 3 }对 6 作旋转操作,那么结果是 { 6, 5, 4, 3, 9, 8, 7 }。用图来表示就是:
同样的迭代器的移动能力会影响算法的效率,或者是应该有一个最小功能原则,STL先将 rotate 定义为一个分发函数,根据不同的迭代器版本调用不同的实现,这里有三个不同的版本的 rotate,返回值是 last + (last - middle)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 template <typename _ForwardIterator>inline _ForwardIteratorrotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { return std ::__rotate(__first, __middle, __last, std ::__iterator_category(__first)); } template <typename _ForwardIterator>_ForwardIterator __rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, forward_iterator_tag) { if (__first == __middle) return __last; else if (__last == __middle) return __first; _ForwardIterator __first2 = __middle; do { std ::iter_swap(__first, __first2); ++__first; ++__first2; if (__first == __middle) __middle = __first2; } while (__first2 != __last); _ForwardIterator __ret = __first; __first2 = __middle; while (__first2 != __last) { std ::iter_swap(__first, __first2); ++__first; ++__first2; if (__first == __middle) __middle = __first2; else if (__first2 == __last) __first2 = __middle; } return __ret; } template <typename _BidirectionalIterator>_BidirectionalIterator __rotate(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, bidirectional_iterator_tag) { if (__first == __middle) return __last; else if (__last == __middle) return __first; std ::__reverse(__first, __middle, bidirectional_iterator_tag()); std ::__reverse(__middle, __last, bidirectional_iterator_tag()); while (__first != __middle && __middle != __last) { std ::iter_swap(__first, --__last); ++__first; } if (__first == __middle) { std ::__reverse(__middle, __last, bidirectional_iterator_tag()); return __last; } else { std ::__reverse(__first, __middle, bidirectional_iterator_tag()); return __first; } } template <typename _RandomAccessIterator>_RandomAccessIterator __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, random_access_iterator_tag) { if (__first == __middle) return __last; else if (__last == __middle) return __first; typedef typename iterator_traits<_RandomAccessIterator>::difference_type _Distance; typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType; _Distance __n = __last - __first; _Distance __k = __middle - __first; if (__k == __n - __k) { std ::swap_ranges(__first, __middle, __middle); return __middle; } _RandomAccessIterator __p = __first; _RandomAccessIterator __ret = __first + (__last - __middle); for (;;) { if (__k < __n - __k) { 前短后长 if (__is_pod(_ValueType) && __k == 1 ) { _ValueType __t = _GLIBCXX_MOVE(*__p); _GLIBCXX_MOVE3(__p + 1 , __p + __n, __p); *(__p + __n - 1 ) = _GLIBCXX_MOVE(__t ); return __ret; } _RandomAccessIterator __q = __p + __k; for (_Distance __i = 0 ; __i < __n - __k; ++ __i) { std ::iter_swap(__p, __q); ++__p; ++__q; } __n %= __k; if (__n == 0 ) return __ret; std ::swap(__n, __k); __k = __n - __k; } else { __k = __n - __k; if (__is_pod(_ValueType) && __k == 1 ) { _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - 1 )); _GLIBCXX_MOVE_BACKWARD3(__p, __p + __n - 1 , __p + __n); *__p = _GLIBCXX_MOVE(__t ); return __ret; } _RandomAccessIterator __q = __p + __n; __p = __q - __k; for (_Distance __i = 0 ; __i < __n - __k; ++ __i) { --__p; --__q; std ::iter_swap(__p, __q); } __n %= __k; if (__n == 0 ) return __ret; std ::swap(__n, __k); } } }
除了这些算法还是其他的的算法,算法的实现都很简单:
search_n:在给定区间内,查找“连续 count 个符合条件之元素”形成的子序列,并返回一个指向这个子序列的迭代器。比如 查找“连续两个8”形成的子序列:iter = search_n(ivec.begin(), ivec.end(), 2, 8)
;查找“连续三个小于8的元素”形成的子序列:iter = search_n(ivec.begin(), ivec.end(), 3, 8, less<int>())
transform:
unique:移除给定区间的重复元素,但是只移除相邻的重复元素,如果想要移除所有的重复元素,可以先排序使得所有的重复元素相邻。unique 返回新区间的尾端,会有残留数据,可以用容器的成员函数 erase 删除残留在后端的数据。
unique_copy:和 unique 类似,但是将结果复制到以 result 为起始位置的容器中。
9. 比较复杂的算法 9.1 lower_bound(应用于有序区间) lower_bound() 是二分查找的一个版本,试图在一个有序区间种寻找 value。如果区间中有和 value 相等的元素,那么就返回一个指向这个元素的迭代器,如果没有相等的元素,那么就返回如果要将 value 插入区间,value应该在的位置,也就是会返回一个迭代器,指向第一个“不小于 value 的元素”,如果 value 比所有的元素都大,那么返回 last。该算法有两个版本,版本1采用 operator< 进行比较,版本2采用函数对象(functor)进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <typename _ForwardIterator, typename _Tp, typename _Compare>_ForwardIterator __lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val, _Compare __comp) { typedef typename iterator_traits<_ForwardIterator>::difference_type _DistanceType; _DistanceType __len = std ::distance(__first, __last); while (__len > 0 ) { _DistanceType __half = __len >> 1 ; _ForwardIterator __middle = __first; std ::advance(__middle, __half); if (__comp(__middle, __val)) { __first = __middle; ++__first; __len = __len - __half - 1 ; } else __len = __half; } return __first; }
9.2 upper_bound(应用于有序区间) upper_bound() 和 lower_bound() 类似,都是二分查找的一个版本,返回“在不破坏顺序的情况下,可插入 value 的最后一个合适的位置”,这里不顺序不被破坏的意思就是排序的状态不变,也就是如果序列本来就是存在value,那么 upper_bound() 返回的是迭代器指向 value 的下一个位置。upper_bound() 同样有两个版本,版本一使用 operator< 进行比较,版本二使用 仿函数 comp 进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 template <typename _ForwardIterator, typename _Tp, typename _Compare>_ForwardIterator __upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val, _Compare __comp) { typedef typename iterator_traits<_ForwardIterator>::difference_type _DistanceType; _DistanceType __len = std ::distance(__first, __last); while (__len > 0 ) { _DistanceType __half = __len >> 1 ; _ForwardIterator __middle = __first; std ::advance(__middle, __half); if (__comp(__val, __middle)) __len = __half; else { __first = __middle; ++__first; __len = __len - __half - 1 ; } } return __first; }
9.3 binary_search binary_search() 是一种二分查找,用于查找给定区间是否有 vulue,返回一个 bool 值,同样两个版本,version1使用 operator< 进行比较,version2使用仿函数进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <typename _ForwardIterator, typename _Tp>bool binary_search (_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val) { _ForwardIterator __i = std ::__lower_bound(__first, __last, __val, __gnu_cxx::__ops::__iter_less_val()); return __i != __last && !(__val < *__i); } template <typename _ForwardIterator, typename _Tp, typename _Compare>bool binary_search (_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val, _Compare __comp) { _ForwardIterator __i = std ::__lower_bound(__first, __last, __val, __gnu_cxx::__ops::__iter_comp_val(__comp)); eturn __i != __last && !bool (__comp(__val, *__i)); }
9.4 next_permutation next_permutation() 和 prev_permutation() 是STL提供的用来计算排列组合关系的两个函数,分别获得前一个排列组合和后一个排列组合。next_permutation() 获取下一个排列,如果没有(已经是最后一个排列),那么就返回 false,否则返回 true, 这是要给 mutation function。同样有两个版本的实现,version1使用元素所提供的 less-than 操作符来决定下一个排列,version2则使用仿函数来决定。 下一个排列其实就是找到下一个更大的数,比如 32654 的下一个数应该是 34256。下一个排列算法 :
从后往前找到两个相邻元素 i 和 ii,并且 i < ii;
继续从后往前找第一个大于 i 的元素j;
swap(i, j);
reverse(ii, last);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 template <typename _BidirectionalIterator>inline bool next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last) { return std ::__next_permutation (__first, __last, __gnu_cxx::__ops::__iter_less_iter()); } template <typename _BidirectionalIterator, typename _Compare>bool __next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { if (__first == __last) return false ; _BidirectionalIterator __i = __first; ++__i; if (__i == __last) return false ; __i = __last; --__i; for (;;) { _BidirectionalIterator __ii = __i; --__i; if (__comp(__i, __ii)) { _BidirectionalIterator __j = __last; while (!__comp(__i, --__j)) {} std ::iter_swap(__i, __j); std ::__reverse(__ii, __last, std ::__iterator_category(__first)); return true ; } if (__i == __first) { std ::__reverse(__first, __last, std ::__iterator_category(__first)); return false ; } } }
9.5 prev_permutation prev_permutation() 获取前一个排列,相当于找到比当前数小,但是最接近当前数的数。算法返回值是bool值,当序列已经升序,没有前一个排列,同样重拍变成升序,实现方面也和 next_permutation() 类似:
从尾部往前找两个相邻元素,使得 i > ii(i前ii后);
从尾部往前找出第一个小于 i 的元素 j;
swap(i, j);
reverse(ii, last);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 template <typename _BidirectionalIterator, typename _Compare>bool __prev_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { if (__first == __last) return false ; _BidirectionalIterator __i = __first; ++__i; if (__i == __last) return false ; __i = __last; --__i; for (;;) { _BidirectionalIterator __ii = __i; --__i; if (__comp(__ii, __i)) { _BidirectionalIterator __j = __last; while (!__comp(--__j, __i)) {} std ::iter_swap(__i, __j); std ::__reverse(__ii, __last, std ::__iterator_category(__first)); return true ; } if (__i == __first) { std ::__reverse(__first, __last, std ::__iterator_category(__first)); return false ; } } }
9.6 random_shuffle random_shuffle() 将给定区间的元素次序随机重拍,也就是在 N! 中可能中选择一种作为结果。random_shuffle()将形成在 N! 种可能种的均匀分布,每种排列的可能概率都相等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <typename _RandomAccessIterator, typename _RandomNumberGenerator>void random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, #if __cplusplus >= 201103L _RandomNumberGenerator&& __rand) #else _RandomNumberGenerator& __rand) #endif { if (__first == __last) return ; for (_RandomAccessIterator __i = __first + 1 ; __i != __last; ++__i) { _RandomAccessIterator __j = __first + __rand((__i - __first) + 1 ); if (__i != __j) std ::iter_swap(__i, __j); } }
9.7 partial_sort / partial_sort_copy partial_sort() 接受三个迭代器,first、middle、last,任务是找出 middle - first 个最小的元素,也就是使得序列中的 middle - first 个最小的元素按照递增排序,放置在区间 [first, middle) 中,其余的 last - middle 个元素放置于区间 [middle, last) 中,但是不保证有序。当然使用 sort() 算法对整个区间排序然后获取前 N 个也可达到获取 N 个最小元素的目的,不这么做的唯一原因就是效率问题。partial_sort() 同样有两个版本,一个是使用 less-than 操作符 operator< 来比较元素,另一个版本是可以提供一个 functor 来比较元素。算法的内部使用 heap sort 来实现 :
使用 make_heap() 将区间 [first, middle) 组织成要给 max-heap;
遍历区间 [middle, last) ,每个元素都和 max-heap 的最大元素(第一个元素)比较,如果小于该最大值,那么就互换;
遍历结束后 [first, middle) 中的所有值已经是整个区间的最小值;
使用 sort_heap 对区间 [first, middle) 排序即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <typename _RandomAccessIterator, typename _Compare>inline void __partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { std ::__heap_select(__first, __middle, __last, __comp); std ::__sort_heap(__first, __middle, __comp); } template <typename _RandomAccessIterator, typename _Compare>void __heap_select(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { std ::__make_heap(__first, __middle, __comp); for (_RandomAccessIterator __i = __middle; __i < __last; ++__i) if (__comp(__i, __first)) std ::__pop_heap(__first, __middle, __i, __comp); }
至于 partial_sort_copy,实现上于 partial_sort 类似,但是将区间[first, last)排序后的结果写道[result_first, result_last)中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 template <typename _InputIterator, typename _RandomAccessIterator,typename _Compare>_RandomAccessIterator __partial_sort_copy(_InputIterator __first, _InputIterator __last, _RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp) { typedef typename iterator_traits<_InputIterator>::value_type _InputValueType; typedef iterator_traits<_RandomAccessIterator> _RItTraits; typedef typename _RItTraits::difference_type _DistanceType; if (__result_first == __result_last) return __result_last; _RandomAccessIterator __result_real_last = __result_first; while (__first != __last && __result_real_last != __result_last) { *__result_real_last = *__first; ++__result_real_last; ++__first; } std ::__make_heap(__result_first, __result_real_last, __comp); while (__first != __last) { if (__comp(__first, __result_first)) std ::__adjust_heap(__result_first, _DistanceType(0 ), _DistanceType(__result_real_last - __result_first), _InputValueType(*__first), __comp); ++__first; } std ::__sort_heap(__result_first, __result_real_last, __comp); return __result_real_last; }
9.8 sort sort() 是所有 STL 提供的算法中最庞大复杂的一个算法,算法接受一对随机访问寄存器,然后将这对寄存器表示的区间范围内的元素按照升序排序,另一个版本则是允许用户提供一个仿函数作为排序的标准。STL中所有的关联容器底部都有排序功能(RB-tree自动排序的功能),所以用不到这个算法。序列式容器 vector、deque和list中,前两个的迭代器是属于随机访问寄存器(random access iterator),因此可以使用 sort,但是 list 的迭代器是 bidirectional iterator,不能使用算法 sort,因此需要调用容器自己的成员函数sort。 为什么泛型算法 sort() 一定要 random access iterator? sort() 算法不是单纯使用某一个算法,而是根据不同的情况使用不同的算法:当数据量大时,首先使用 quick sort 分段递归排序,一旦分段排序数据量足够小,就可以使用 insertion sort,而如果递归的层次过深,还会改用 heap sort:
insertion_sort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 template <typename _RandomAccessIterator, typename _Compare>void __insertion_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { if (__first == __last) return ; for (_RandomAccessIterator __i = __first + 1 ; __i != __last; ++__i) { if (__comp(__i, __first)) { typename iterator_traits<_RandomAccessIterator>::value_type __val = _GLIBCXX_MOVE(*__i); _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1 ); *__first = _GLIBCXX_MOVE(__val); } else std ::__unguarded_linear_insert(__i, __gnu_cxx::__ops::__val_comp_iter(__comp)); } } template <typename _RandomAccessIterator, typename _Compare>void __unguarded_linear_insert(_RandomAccessIterator __last, _Compare __comp) { typename iterator_traits<_RandomAccessIterator>::value_type __val = _GLIBCXX_MOVE(*__last); _RandomAccessIterator __next = __last; --__next; while (__comp(__val, __next)) { *__last = _GLIBCXX_MOVE(*__next); __last = __next; --__next; } *__last = _GLIBCXX_MOVE(__val); }
quick_sort 🚗🚗🚗🚗🚗🚗🚗🚗😁 insert_sort 的时间复杂度是O(N2 ),显然不适合用来处理大量数据,而 quick_sort 就是用来处理大量数据,平均时间复杂度为 O(NlogN),最坏情况(待排序序列已经是正序或者逆序,那么递归树退化为单支的链表,深度最大)为O(N2 )。一般来说,平均时间复杂度为O(NlogN)的算法有快排、堆排、归并,那么为什么STL要选择快排呢?这是因为在这三种算法中,归并需要更大的空间复杂度,而快排和堆排二者表面数据相当,但是由于快排使用分治的思想,每次比较的数据都是在一段区域内,能够很好利用 CPU cache (空间局部性原理),而堆排每次都需要从堆中拿出元素替换,不能利用好局部性原理。事实上这可能也是为什么快排表现更好的一个原因。假设S是待排序序列,快排算法如下:
如果S的元素个数是 0 或者 1,结束;
取 S 的任何一个元素作为枢纽 v (根据 v 将 S 划分为两部分);
为了避免输入数据不够随机,也就是已经有序带来的效率影响问题
在划分上通常采用 median-of-three 的方法,也就是取首、中、尾三个元素的中间值作为v;
而为了能够快速或者中间元素,输入迭代器必须是 random access iterator
将 S 划分为 L,R 两部分,其中 L 中的所有元素都小于 v,R 中的所有元素都大于等于 v;
对 L,R 递归执行快排
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <typename _RandomAccessIterator, typename _Compare>_RandomAccessIterator __unguarded_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, _RandomAccessIterator __pivot, _Compare __comp) { while (true ) { while (__comp(__first, __pivot)) ++__first; --__last; while (__comp(__pivot, __last)) --__last; if (!(__first < __last)) return __first; std ::iter_swap(__first, __last); ++__first; } }
调用 Insertion Sort 的阈值 前面说到当数据量小的时候可以使用 Insertion Sort,那么具体是多小才可以调用呢?事实上这个问题并没有定数,具体情况要根据设备而有不同,可能是5,可能是20,也可能是中间的一个值。
introSort(内省排序) 所谓内省排序(Introspective Sort)是多种混合排序算法,它的行为在大多数情况下和 median-of-three Quick Sort 完全相同,但是当分割行为有恶化为二次(N2 )的倾向时,能够自己检测,转而调用 Heap Sort,从而使效率维持在 Heap Sort O(NlogN)。
sort() 整合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 template <typename _RandomAccessIterator>inline void sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { std ::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter()); } template <typename _RandomAccessIterator, typename _Compare>inline void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { std ::__sort(__first, __last, __gnu_cxx::__ops::__iter_comp_iter(__comp)); } template <typename _RandomAccessIterator, typename _Compare>inline void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { if (__first != __last) { std ::__introsort_loop(__first, __last, std ::__lg(__last - __first) * 2 , __comp); std ::__final_insertion_sort(__first, __last, __comp); } } template <typename _RandomAccessIterator, typename _Compare>inline void __partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { std ::__heap_select(__first, __middle, __last, __comp); std ::__sort_heap(__first, __middle, __comp); } template <typename _RandomAccessIterator, typename _Compare>inline _RandomAccessIterator__unguarded_partition_pivot(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { _RandomAccessIterator __mid = __first + (__last - __first) / 2 ; std ::__move_median_to_first(__first, __first + 1 , __mid, __last - 1 , __comp); return std ::__unguarded_partition(__first + 1 , __last, __first, __comp); } template <typename _RandomAccessIterator, typename _Size, typename _Compare>void __introsort_loop(_RandomAccessIterator __first, _RandomAccessIterator __last, _Size __depth_limit, _Compare __comp) { while (__last - __first > int (_S_threshold)) { if (__depth_limit == 0 ) { std ::__partial_sort(__first, __last, __last, __comp); return ; } --__depth_limit; _RandomAccessIterator __cut = std ::__unguarded_partition_pivot(__first, __last, __comp); std ::__introsort_loop(__cut, __last, __depth_limit, __comp); __last = __cut; } }
9.9 equal_range(应用于有序区间) equal_range() 是二分查找的一个版本,在以排序的区间找 value,返回一对迭代器(pair),i和j,其中 i 是在不破坏次序的情况下可插入的第一给位置(lower_bound),j 是在不破坏次序的情况下可插入的最后一个位置(upper_bound)。函数同样有两个版本,一个用 operator< 进行比较,另一个版本使用仿函数 comp。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 template <typename _ForwardIterator, typename _Tp,typename _CompareItTp, typename _CompareTpIt>pair<_ForwardIterator, _ForwardIterator> __equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val, _CompareItTp __comp_it_val, _CompareTpIt __comp_val_it) { typedef typename iterator_traits<_ForwardIterator>::difference_type _DistanceType; _DistanceType __len = std ::distance(__first, __last); while (__len > 0 ) { _DistanceType __half = __len >> 1 ; _ForwardIterator __middle = __first; std ::advance(__middle, __half); if (__comp_it_val(__middle, __val)) { __first = __middle; ++__first; __len = __len - __half - 1 ; } else if (__comp_val_it(__val, __middle)) __len = __half; else { _ForwardIterator __left = std ::__lower_bound(__first, __middle, __val, __comp_it_val); std ::advance(__first, __len); _ForwardIterator __right = std ::__upper_bound(++__middle, __first, __val, __comp_val_it); return pair<_ForwardIterator, _ForwardIterator>(__left, __right); } } return pair<_ForwardIterator, _ForwardIterator>(__first, __first); }
9.10 inplace_merge inplace_merge() 将两个连在一起而且分别有序的序列结合成一个序列,并保持有序,如果两个子序列有相等的元素,第一个子序列的元素会在前。算法有两个版本,version1使用 operator< 进行比较,version2则使用用户提供的仿函数进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 template <typename _BidirectionalIterator, typename _Compare>void __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) { typedef typename iterator_traits<_BidirectionalIterator>::value_type _ValueType; typedef typename iterator_traits<_BidirectionalIterator>::difference_type _DistanceType; if (__first == __middle || __middle == __last) return ; const _DistanceType __len1 = std ::distance(__first, __middle); const _DistanceType __len2 = std ::distance(__middle, __last); typedef _Temporary_buffer<_BidirectionalIterator, _ValueType> _TmpBuf; _TmpBuf __buf(__first, __last); if (__buf.begin() == 0 ) std ::__merge_without_buffer (__first, __middle, __last, __len1, __len2, __comp); else std ::__merge_adaptive (__first, __middle, __last, __len1, __len2, __buf.begin(), _DistanceType(__buf.size()), __comp); } template <typename _BidirectionalIterator, typename _Distance,typename _Compare>void __merge_without_buffer(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Distance __len1, _Distance __len2, _Compare __comp) { if (__len1 == 0 || __len2 == 0 ) return ; if (__len1 + __len2 == 2 ) { if (__comp(__middle, __first)) std ::iter_swap(__first, __middle); return ; } _BidirectionalIterator __first_cut = __first; _BidirectionalIterator __second_cut = __middle; _Distance __len11 = 0 ; _Distance __len22 = 0 ; if (__len1 > __len2) { __len11 = __len1 / 2 ; std ::advance(__first_cut, __len11); __second_cut = std ::__lower_bound(__middle, __last, *__first_cut, __gnu_cxx::__ops::__iter_comp_val(__comp)); __len22 = std ::distance(__middle, __second_cut); } else { __len22 = __len2 / 2 ; std ::advance(__second_cut, __len22); __first_cut = std ::__upper_bound(__first, __middle, *__second_cut, __gnu_cxx::__ops::__val_comp_iter(__comp)); __len11 = std ::distance(__first, __first_cut); } std ::rotate(__first_cut, __middle, __second_cut); _BidirectionalIterator __new_middle = __first_cut; std ::advance(__new_middle, std ::distance(__middle, __second_cut)); std ::__merge_without_buffer(__first, __first_cut, __new_middle, __len11, __len22, __comp); std ::__merge_without_buffer(__new_middle, __second_cut, __last, __len1 - __len11, __len2 - __len22, __comp); } template <typename _BidirectionalIterator, typename _Distance, typename _Pointer, typename _Compare>void __merge_adaptive(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Distance __len1, _Distance __len2, _Pointer __buffer, _Distance __buffer_size, _Compare __comp) { if (__len1 <= __len2 && __len1 <= __buffer_size) { _Pointer __buffer_end = _GLIBCXX_MOVE3(__first, __middle, __buffer); std ::__move_merge_adaptive(__buffer, __buffer_end, __middle, __last, __first, __comp); } else if (__len2 <= __buffer_size) { _Pointer __buffer_end = _GLIBCXX_MOVE3(__middle, __last, __buffer); std ::__move_merge_adaptive_backward(__first, __middle, __buffer, __buffer_end, __last, __comp); } else { _BidirectionalIterator __first_cut = __first; _BidirectionalIterator __second_cut = __middle; _Distance __len11 = 0 ; _Distance __len22 = 0 ; if (__len1 > __len2) { __len11 = __len1 / 2 ; std ::advance(__first_cut, __len11); __second_cut = std ::__lower_bound(__middle, __last, *__first_cut, __gnu_cxx::__ops::__iter_comp_val(__comp)); __len22 = std ::distance(__middle, __second_cut); } else { __len22 = __len2 / 2 ; std ::advance(__second_cut, __len22); __first_cut = std ::__upper_bound(__first, __middle, *__second_cut, __gnu_cxx::__ops::__val_comp_iter(__comp)); __len11 = std ::distance(__first, __first_cut); } _BidirectionalIterator __new_middle = std ::__rotate_adaptive(__first_cut, __middle, __second_cut, __len1 - __len11, __len22, __buffer, __buffer_size); std ::__merge_adaptive(__first, __first_cut, __new_middle, __len11, __len22, __buffer, __buffer_size, __comp); std ::__merge_adaptive(__new_middle, __second_cut, __last, __len1 - __len11, __len2 - __len22, __buffer, __buffer_size, __comp); } }
9.11 nth_element nth_element()
9.12 merge sort 还真的全都忘记了!🐷