前言
在上一小节中我们分析了stl_algobase.h
中的算法,虽然都是一些比较基础的算法,但是了解其中的泛化以及特化的思想是很重要的。
在本小节中我们将分析stl_algo.h
中的算法,里面的大部分算法也很基础,比较复杂的我们放在另外的小节分析。
各算法的实现
for_each
遍历[first, last)
,每个元素使用仿函数f
进行处理。
注意传入的迭代器类型是InputIterator
,所以可能不支持赋值。
template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f) {
for ( ; first != last; ++first)
f(*first);
return f;
}
find
该函数作用是寻找[first, last)
范围内值为value
的元素,并返回指向其的迭代器。如果没找到,返回last
。
注意要求迭代器的类型至少是可读的。
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value) {
while (first != last && *first != value) ++first;
return first;
}
find_if
该函数的作用是根据pred
仿函数来查找[first, last)
范围内第一个令pred
返回true
的元素,如果没有,返回last
。同样也要求迭代器类型至少是可读。
template <class InputIterator, class Predicate>
InputIterator find_if(InputIterator first, InputIterator last,
Predicate pred) {
while (first != last && !pred(*first)) ++first;
return first;
}
adjacent_find
该函数的作用是找出第一组符合条件的相邻元素。第一个版本是找到相邻的重复元素,而第二个版本是通过传入的binary_pred
作为条件。
这里要求迭代器的类型是ForwardIterator
。若找到符合条件的,则返回指向该元素的迭代器,否则返回last
。
template <class ForwardIterator>
ForwardIterator adjacent_find(ForwardIterator first, ForwardIterator last) {
if (first == last) return last;
ForwardIterator next = first;
while(++next != last) {
if (*first == *next) return first;
first = next;
}
return last;
}
template <class ForwardIterator, class 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;
}
count
该函数的作用是计算[first, last)
范围内,值为value
的元素的个数。要求迭代器至少可读。
以下有两个版本,一个是传入n的引用来计数,另一个是自己声明计数器然后返回。
//传入n的引用进行计数
template <class InputIterator, class T, class Size>
void count(InputIterator first, InputIterator last, const T& value,
Size& n) {
for ( ; first != last; ++first)
if (*first == value)
++n;
}
/* 通过traits技法获取difference_type来定义计数器
* 注意这里使用了typename关键字
* 它的作用是告诉编译器,typename后面的是iterator_traits<InputIterator>::difference_type是一个嵌套的类型,而不是变量成员
* 如果类型是依赖模板参数的,在使用前需要加上typename表明是类型
* 但是如果是继承里的基类列表或者在类的初始化成员列表中就不用使用
* typename大概的作用就这样,它和class并不是完全一样的,这点需要注意
* 感兴趣可以去看看《effectiveC++》或者查阅相关资料
* 后面我也会总结出来
*/
template <class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last, const T& value) {
typename iterator_traits<InputIterator>::difference_type n = 0;
for ( ; first != last; ++first)
if (*first == value)
++n;
return n;
}
count_if
该函数的作用是计算[first, last)
范围内,满足pred
仿函数条件的元素的个数。
template <class InputIterator, class Predicate, class Size>
void count_if(InputIterator first, InputIterator last, Predicate pred,
Size& n) {
for ( ; first != last; ++first)
if (pred(*first))
++n;
}
search
该函数中的作用是在序列一[first1, last1)
的区间中,寻找序列二[first2, last2)
的首次出现点。如果没有,则返回迭代器last1
;如果找到了,返回与第二个序列匹配的指向第一个元素的迭代器。
还有另外一个版本的,提供了自己的比较仿函数binary_pred
而不是直接比较两元素是否相等。
template <class ForwardIterator1, class ForwardIterator2, class Distance1,
class Distance2>
ForwardIterator1 __search(ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, ForwardIterator2 last2,
Distance1*, Distance2*) {
//计算[first1, last1)的距离d1
Distance1 d1 = 0;
distance(first1, last1, d1);
//计算[first2, last2)的距离d2
Distance2 d2 = 0;
distance(first2, last2, d2);
/* 如果第一个序列比第二个序列还短
* 那肯定没有满足的条件的子序列,直接返回last1
*/
if (d1 < d2) return last1;
//current1指向第一个序列的第一个元素
ForwardIterator1 current1 = first1;
//current2指向第二个序列的第一个元素
ForwardIterator2 current2 = first2;
//遍历序列二
while (current2 != last2)
//尝试找到相等的元素,找到了则往后移动
if (*current1 == *current2) {
++current1;
++current2;
}
//若当前元素不相等
else {
//若d1=d2,但是此时已经有元素不相等了
//则不可能满足条件了,直接返回
if (d1 == d2)
return last1;
else {
//此时将current1后移,再尝试与current2比较
current1 = ++first1;
current2 = first2;
//更新d1
--d1;
}
}
return first1;
}
//search函数,运用distance_type获取到相关类型
template <class ForwardIterator1, class ForwardIterator2>
inline ForwardIterator1 search(ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, ForwardIterator2 last2)
{
return __search(first1, last1, first2, last2, distance_type(first1),
distance_type(first2));
}
search_n
该函数的作用是在[first, last)
区间中,查找连续count
个符合条件的元素形成的子序列,如若有,则返回指向该子序列的起始处的迭代器;如果没有,则返回last
。
要求迭代器的类型是ForwardIterator
及其派生类。还有一个版本是提供了binary_pred
仿函数进行比较,这里就不列出源码了,避免太多冗长了。
template <class ForwardIterator, class Integer, class T>
ForwardIterator search_n(ForwardIterator first, ForwardIterator last,
Integer count, const T& value) {
//count小于等于0,直接返回first
if (count <= 0)
return first;
else {
//调用find函数,先找到第一个值为value的元素,并返回指向其的迭代器
//如果没有值为value的元素,返回last
first = find(first, last, value);
//遍历更新后的[first, last)中的元素
//first是指向序列中与value相等的第一个元素或者是last
while (first != last) {
//n表示剩下需要相等的元素个数
Integer n = count - 1;
ForwardIterator i = first;
++i;
//i指向需要比较的元素
//开始循环比较(因为要求连续的)
while (i != last && n != 0 && *i == value) {
++i;
--n;
}
//n为0代表已经找到满足条件的序列了,返回
if (n == 0)
return first;
else
//否则找到下一个值为value1的元素为first,重新开始比较
first = find(i, last, value);
}
//遍历完序列还未找到满足条件的序列
//返回last
return last;
}
}
swap_ranges
该函数的作用是将[first1, last1)
和[first2, first2 + (last1 - first1))
这两个序列的元素互换。
当第二个序列的长度小于第一个序列或者这两个序列在同一个容器互相重叠时,会导致不可预期的结果。
template <class ForwardIterator1, class ForwardIterator2>
ForwardIterator2 swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2) {
for ( ; first1 != last1; ++first1, ++first2)
//调用iter_swap函数
iter_swap(first1, first2);
return first2;
}
transform
该函数的作用是遍历[first, last)
范围内的元素,并对每一个元素使用仿函数op
,并将所有结果作为一个新的序列。还有一个版本是使用binary_op
对[first1, last1)
以及[first2, first2 + (last1 - first1))
这两个序列的每对元素进行求值,将所有结果形成一个新的序列返回。
template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform(InputIterator first, InputIterator last,
OutputIterator result, UnaryOperation op) {
for ( ; first != last; ++first, ++result)
*result = op(*first);
return result;
}
template <class InputIterator1, class InputIterator2, class OutputIterator,
class BinaryOperation>
OutputIterator transform(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, OutputIterator result,
BinaryOperation binary_op) {
for ( ; first1 != last1; ++first1, ++first2, ++result)
//作用于一对元素上
*result = binary_op(*first1, *first2);
return result;
}
replace
该函数的作用是将[first, last)
序列中所有值为old_value
的元素的值换成new_value
。要求迭代器是可读写的类型。
template <class ForwardIterator, class T>
void replace(ForwardIterator first, ForwardIterator last, const T& old_value,
const T& new_value) {
for ( ; first != last; ++first)
if (*first == old_value) *first = new_value;
}
replace_if
该函数的作用是将[first, last)
序列中所有满足让pred
仿函数返回true的元素的值换成new_value
。要求迭代器是可读写的类型。
template <class ForwardIterator, class Predicate, class T>
void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred,
const T& new_value) {
for ( ; first != last; ++first)
if (pred(*first)) *first = new_value;
}
replace_copy
该函数的作用同样也是将[first, last)
序列中所有值为old_value
的元素的值换成new_value
,其他的值保留。不过结果都存在新的序列上。最后会返回新的序列的最后一个元素的下一个位置。
template <class InputIterator, class OutputIterator, class T>
OutputIterator replace_copy(InputIterator first, InputIterator last,
OutputIterator result, const T& old_value,
const T& new_value) {
for ( ; first != last; ++first, ++result)
*result = *first == old_value ? new_value : *first;
return result;
}
replace_copy_if
这个版本是提供仿函数pred
作为比较的函数,而不是判断与old_value
是否相等。
template <class Iterator, class OutputIterator, class Predicate, class T>
OutputIterator replace_copy_if(Iterator first, Iterator last,
OutputIterator result, Predicate pred,
const T& new_value) {
for ( ; first != last; ++first, ++result)
*result = pred(*first) ? new_value : *first;
return result;
}
generate
该函数的作用是将[first, last)
序列中的元素的值都赋成仿函数gen
的运算结果
template <class ForwardIterator, class Generator>
void generate(ForwardIterator first, ForwardIterator last, Generator gen) {
for ( ; first != last; ++first)
*first = gen();
}
generate_n
该函数的作用是将[first, last)
序列中的前n个元素的值都赋成仿函数gen
的运算结果
template <class OutputIterator, class Size, class Generator>
OutputIterator generate_n(OutputIterator first, Size n, Generator gen) {
for ( ; n > 0; --n, ++first)
*first = gen();
return first;
}
remove_copy
该函数的作用是移除[first, last)
区间中所有与value
相等的元素,不过这些操作的结果都反应到新序列中,原序列不变。最后返回新序列的最后一个元素的下一个位置。
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;
++result;
}
return result;
}
remove_copy_if
它传入了仿函数pred
作为比较的操作,而不是直接判断是否与value
相等。
remove_copy
和remove_copy_if
都没有作用在原序列上,而对应的remove
以及remove_if
则作用在原序列上,这里就不列出代码了。
template <class InputIterator, class OutputIterator, class 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;
}
reverse
该函数的作用是反转[first, last)
序列,是在原序列上进行操作,同样的还有另外一个版本reverse_copy
,将结果存在新序列上,没有太大必要再列出。
/* 可以看到__reverse有两个版本,一个是针对BidirectionalIterator型的
* 另一个针对RandomAccessIterator型
* 这样做无非是为了效率
*/
template <class BidirectionalIterator>
void __reverse(BidirectionalIterator first, BidirectionalIterator last,
bidirectional_iterator_tag) {
//刚开始看的时候发现只是iter_swap(first++, last)的操作根本没法反转啊
while (true)
//原来这里的last是往前移了的,开始没有注意到
if (first == last || first == --last)
return;
else
iter_swap(first++, last);
}
//当迭代器类型是RandomAccessIterator时,支持first < last这样的操作
//于是我们可以从两端往中间扫,然后交换元素
template <class RandomAccessIterator>
void __reverse(RandomAccessIterator first, RandomAccessIterator last,
random_access_iterator_tag) {
while (first < last) iter_swap(first++, --last);
}
//通过iterator_category获取到迭代器的相应型别
template <class BidirectionalIterator>
inline void reverse(BidirectionalIterator first, BidirectionalIterator last) {
__reverse(first, last, iterator_category(first));
}
unique_copy
该函数的作用是将[first, last)
中的元素复制到新序列上(如果有重复的元素,只会赋值其中的第一个元素)。最后返回指向新序列最后一个元素的下一个位置的迭代器。
//要注意传入的result是ForwardIterator型的,代表可以读/写及单步移动。
template <class InputIterator, class ForwardIterator>
ForwardIterator __unique_copy(InputIterator first, InputIterator last,
ForwardIterator result, forward_iterator_tag) {
//首先将新序列result的值赋为第一个元素的值
*result = *first;
//遍历原序列
while (++first != last)
//若值不重复,则result指向下一个位置,然后将first指向的值赋给它
if (*result != *first) *++result = *first;
return ++result;
}
//这个版本的result的类型是OutputIterator型的(只写)
//所以不能像上个版本那样取值判断(*result != *first)
template <class InputIterator, class OutputIterator, class T>
OutputIterator __unique_copy(InputIterator first, InputIterator last,
OutputIterator result, T*) {
//将需要比较的元素用value存起来
T value = *first;
*result = value;
while (++first != last)
//比较value,若不等于,则更新value
if (value != *first) {
value = *first;
*++result = value;
}
return ++result;
}
//调用以上两个版本的其中之一
template <class InputIterator, class OutputIterator>
inline OutputIterator __unique_copy(InputIterator first, InputIterator last,
OutputIterator result,
output_iterator_tag) {
return __unique_copy(first, last, result, value_type(first));
}
//调用__unique_copy函数
template <class InputIterator, class OutputIterator>
inline OutputIterator unique_copy(InputIterator first, InputIterator last,
OutputIterator result) {
//首先处理特殊情况
if (first == last) return result;
return __unique_copy(first, last, result, iterator_category(result));
}
//以上的函数都有另外一个版本的,即提供binary_pred仿函数进行判断,这里就不列出了。
unique
template <class ForwardIterator>
ForwardIterator unique(ForwardIterator first, ForwardIterator last) {
/* 先找到相邻重复元素的起点(这样可以省去前面不重复元素的比较,省时)
* 然后调用unique_copy完成,由于新序列也就是原序列,所以最后导致的结果是末尾可能有残留的数据
* 比如{0, 1, 2, 3, 3, 4, 5},结果就是{0, 1, 2, 3, 4, 5, 5}
* 毕竟原序列的大小是不会变的
first = adjacent_find(first, last);
return unique_copy(first, last, first);
}
小结
关于stl_algo.h
中的算法,除了一些没必要列出的还剩下一些较复杂的算法,这些算法我们放在另外的小节分析。
其实本小节分析的算法大多都比较简单,没有涉及到什么复杂的操作。不过像search
以及reverse
还有unique_copy
这类还是值得一读的,因为涉及到迭代器的特性不同而采取了不同的方法进行处理,达到最佳效率的思想。