STL中的算法小结

 

(1)头文件

STL的算法头文件包含<algorithm>,某些STL算法用于数值处理,被定义于头文件<numeric>中。

所有STL算法都被设计用来处理一个或多个迭代器区间,第一个区间通常以起点和终点表示,至于其他区间,多数情况下你只需提供起点便足以,其终点可以自动以第一个区间的元素数量推断出来,调用者必须保证这些区间的有效性。

STL算法采用覆盖模式而非安插模式,所以调用者必须保证目标区间拥有足够的元素空间,当然你也可以运用特殊的安插型迭代器将覆盖模式改变为安插模式。

 (2)算法

for_each()算法

常用算法,算法定义:

UnaryProc for_each (InputIterator beg, InputIterator end, UnaryProc op);

PS:1 对区间[beg, end)中的每一个元素调用op(elem)
   2 返回op(已在算法内部被变动过)的一个副本
   3 op的任何返回值都会被忽略
   4 op可以变动元素
   5 复杂度:线性


元素计数算法

算法定义:

difference_type count (InputIterator beg, InputIterator end, const T& value);
difference_type count_if (InputIterator beg, InputIterator end, UnaryPredicate op);

PS:1 第一形式会计算区间[beg, end)中的元素等于value的元素个数
   2 第二形式会计算区间[beg, end)中令以下一元判断式结果为true的元素个数:op(elem)
   3 返回值型别为difference_type,是表现迭代器间距的型别
   4 注意op在函数调用过程中不应该改变自身状态
   5 op不应该改动传进来的参数
   6 关联式容器(set/multiset,map/multimap)提供了一个等效的成员函数count()用来计算等于某个value或key的元素个数
   7 时间复杂度:线性

最大最小值算法

算法定义:

InputIterator min_element (InputIterator beg, InputIterator end);
InputIterator min_element (InputIterator beg, InputIterator end, CompFunc op);
InputIterator max_element (InputIterator beg, InputIterator end);
InputIterator max_element (InputIterator beg, InputIterator end, CompFunc op);

PS:1 所有这些算法都返回区间[beg, end)中的最大或最小值的位置
   2 上述无op参数版本以operator<进行元素比较
   3 op用来比较两个元素:op(elem1, elem2)如果第一个元素小于第二个元素,应当返回true
   4 如果存在多个最大或最小值,上述算法返回找到的第一个最大或最小值
   5 op不应该改动传进去的参数
   6 时间复杂度:线性

搜寻元素算法

算法定义:

InputIterator find (InputIterator beg, InputIterator end, const T& value);
InputIterator find_if (InputIterator beg, InputIterator end, UnaryPredicate op);

PS:1 第一形式返回区间[beg, end)中的第一个“元素值等于value”的元素位置
   2 第二形式返回区间[beg, end)中令一元判断式op(elem)结果为true的第一个元素的位置
   3 如果没有找到匹配元素,两种形式都返回end
   4 注意op在函数调用过程中不应该改变自身状态
   5 op不应该改动传进来的参数
   6 如果是已序区间,应使用lower_bound(),upper_bound(),equal_range()或binary_search()算法以获取更高的性能
   7 关联式容器(set/multiset,map/multimap)提供了一个等效的成员函数find(),拥有对数时间复杂度
   8 时间复杂度:线性

InputIterator search_n (InputIterator beg, InputIterator end, Size count, const T& value);
InputIterator search_n (InputIterator beg, InputIterator end, Size count, const T& value, BinaryPredicate op);

PS:1 第一形式返回区间[beg, end)中的第一组“连续count个元素值全等于value”的元素位置
   2 第二形式返回区间[beg, end)中的第一组“连续count个元素使op(elem, value)结果为true”的元素位置
   3 如果没有找到匹配元素,两种形式都返回end
   4 注意op在函数调用过程中不应该改变自身状态
   5 op不应该改动传进来的参数
   6 时间复杂度:线性

ForwardIterator1 search (ForwardIterator1 beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd);
ForwardIterator1 search (ForwardIterator1 beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd, BinaryPredicate op);

PS:1 两种形式都返回区间[beg, end)内“和区间[searchBeg, searchEnd)完全吻合”的第一个子区间内的第一个元素位置
   2 第一形式中,子区间元素必须完全等于[searchBeg, searchEnd)的元素
   3 第二形式中,子区间元素和[searchBeg, searchEnd)的对应元素必须使op(elem, searchElem)结果为true
   4 如果没有找到匹配子区间,两种形式都返回end
   5 注意op在函数调用过程中不应该改变自身状态
   6 op不应该改动传进来的参数
   7 时间复杂度:线性

ForwardIterator find_end (ForwardIterator beg, ForwardIterator end, ForwardIterator searchBeg, ForwardIterator searchEnd);
ForwardIterator find_end (ForwardIterator beg, ForwardIterator end, ForwardIterator searchBeg, ForwardIterator searchEnd, BinaryPredicate op);

PS:1 两种形式都返回区间[beg, end)内“和区间[searchBeg, searchEnd)完全吻合”的最后一个子区间内的第一个元素位置
   2 第一形式中,子区间元素必须完全等于[searchBeg, searchEnd)的元素
   3 第二形式中,子区间元素和[searchBeg, searchEnd)的对应元素必须使op(elem, searchElem)结果为true
   4 如果没有找到匹配子区间,两种形式都返回end
   5 注意op在函数调用过程中不应该改变自身状态
   6 op不应该改动传进来的参数
   7 时间复杂度:线性

ForwardIterator find_first_of (ForwardIterator1 beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd);
ForwardIterator find_first_of (ForwardIterator1 beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd, BinaryPredicate op);

PS:1 第一形式返回第一个“既在区间[beg, end)中出现,也在区间[searchBeg, searchEnd)中出现”的元素位置
   2 第二形式返回区间[beg, end)中的第一个这样的元素:他和区间[searchBeg, searchEnd)内的每一个元素进行op(elem, searchElem)结果都为ture
   3 如果没有找到匹配元素,两种形式都返回end
   4 注意op在函数调用过程中不应该改变自身状态
   5 op不应该改动传进来的参数
   6 你可以使用逆向迭代器来搜寻最后一个这样的元素
   7 时间复杂度:线性

InputIterator adjacent_find (InputIterator beg, InputIterator end);
InputIterator adjacent_find (InputIterator beg, InputIterator end, BinaryPredicate op);

PS:1 第一形式返回区间[beg, end)中的第一对“连续两个相等元素”之中的第一个元素位置
   2 第二形式返回区间[beg, end)中的第一对“连续两个元素均使op(elem, nextElem)结果为true“的其中第一个元素位置
   3 如果没有找到吻合元素,两种形式都返回end
   4 注意op在函数调用过程中不应该改变自身状态
   5 op不应该改动传进来的参数
   6 时间复杂度:线性

bool equal (InputIterator1 beg, InputIterator1 end, InputIterator2 cmpBeg);
bool equal (InputIterator1 beg, InputIterator1 end, InputIterator2 cmpBeg, BinaryPredicate op);

PS:1 第一形式判断区间[beg, end)内的元素是否都和以cmpBeg开头的区间内的元素相等
   2 第二形式判断区间[beg, end)内的元素和以cmpBeg开头的区间内的对应元素是否都能使op(elem, cmpElem)结果为true
   3 调用者必须保证以cmpBeg开头的区间具有足够的元素
   4 当序列不相等时,如果想要了解其间的不同,应使用mismatch()算法
   5 注意op在函数调用过程中不应该改变自身状态
   6 op不应该改动传进来的参数
   7 时间复杂度:线性

pair<InputIterator1, InputIterator2> mismatch (InputIterator1 beg, InputIterator1 end, InputIterator2 cmpBeg);
pair<InputIterator1, InputIterator2> mismatch (InputIterator1 beg, InputIterator1 end, InputIterator2 cmpBeg, BinaryPredicate op);

PS:1 第一形式返回区间[beg, end)和以cmpBeg开头的区间之中的第一组两两相异的对应元素
   2 第二形式返回区间[beg, end)和以cmpBeg开头的区间之中的第一组”使op(elem, cmpElem)结果为false“的对应元素
   3 如果没有找到相异点,就返回一个pair,以end和第二序列的对应元素组成。这并不意味着两个序列相等,因为第二序列有可能包含更多的元素
   4 调用者必须保证以cmpBeg开头的区间具有足够的元素
   5 如果想要了解两个序列是否相等,应使用equal()算法
   6 注意op在函数调用过程中不应该改变自身状态
   7 op不应该改动传进来的参数
   8 时间复杂度:线性

bool lexicographical_compare (InputIterator1 beg1, InputIterator1 end1, InputIterator2 beg2, InputIterator2 end2);
bool lexicographical_compare (InputIterator1 beg1, InputIterator1 end1, InputIterator2 beg2, InputIterator2 end2, CompFunc op);

PS:1 两种形式都用来判断区间[beg1, end1)的元素是否小于区间[beg2, end2)的元素。所谓”小于“是指本着”字典次序“的意义
   2 第一形式使用operator<
   3 第二形式使用op(elem1, elem2)来判断
   4 注意op在函数调用过程中不应该改变自身状态
   5 op不应该改动传进来的参数
   6 时间复杂度:线性

(8)复制元素算法:
OutputIterator copy (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
BidirectionalIterator1 copy_backward (BidirectionalIterator1 sourceBeg, BidirectionalIterator1 sourceEnd, BidirectionalIterator2 destEnd);
1这两个算法都将源区间[sourceBeg, sourceEnd)中的所有元素复制到以destBeg为起点或以destEnd为终点的目标区间里去
2返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
3destBeg或destEnd不可处于[sourceBeg, sourceEnd)区间内
4copy()正向遍历序列,copy_backward()逆向遍历序列
5STL没有所谓的copy_if()算法,所以如果要复制符合某特定准则的元素,请使用remove_copy_if()算法
6如果希望在复制过程中逆转元素次序,应该使用reverse_copy()
7调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
8如果想把容器内的所有元素赋值给另一容器,应当使用assignment操作符(当两个容器的型别相同时)或者使用容器的assign()成员函数(当两个容器的型别不同时)
9如果希望在复制过程中删除某元素,请使用remove_copy()和remove_copy_if()算法
10如果希望在复制过程中改变元素,请使用transform()或replace_copy()算法
11时间复杂度:线性

(9)转换元素算法:
OutputIterator transform (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, UnaryFunc op);
1针对源区间[sourceBeg, sourceEnd)中的每一个元素调用op(elem)并将结果写到以destBeg为起点的目标区间
2返回目标区间内最后一个被转换的元素的下一个位置,也就是第一个未被覆盖的元素的位置
3调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
4sourceBeg和destBeg可以相同,因此你可以使用这个算法来变动某一序列内的元素
5如果想以某值来替换符合某一标准的元素,应使用replace()算法
6时间复杂度:线性

OutputIterator transform (InputIterator1 source1Beg, InputIterator1 source1End, InputIterator2 source2Beg, OutputIterator destBeg, BinaryFunc op);
1针对第一个源区间[source1Beg, source1End)以及从source2Beg开始的第二个源区间的对应元素调用op(source1Elem, source2Elem)并将结果写到以destBeg起始的目标区间
2返回目标区间内最后一个被转换的元素的下一个位置,也就是第一个未被覆盖的元素的位置
3调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
4调用者必须保证第二源区间有足够空间(至少拥有和第一源区间相同的空间大小)
5source1Beg,source2Beg,destBeg可以相同,因此你可以让元素自己和自己结合然后将结果覆盖至某个序列
6时间复杂度:线性

(10)互换元素内容算法:
ForwardIterator2 swap_ranges (ForwardIterator1 beg1, ForwardIterator1 end1, ForwardIterator2 beg2);
1将区间[beg1, end1)内的元素和从beg2开始的区间内的对应元素互换
2返回第二区间中的最后一个被交换元素的下一位置
3调用者必须保证目标区间有足够空间
4两区间不得重叠
5如果要将相同型别的两个容器内的全部元素互换,应使用swap()成员函数这样通常更快
6时间复杂度:线性

(11)赋值算法:
void fill (ForwardIterator beg, ForwardIterator end, const T& newValue);
void fill_n (OutputIterator beg, Size num, const T& newValue);
1fill()将区间[beg, end)内的每一个元素都赋予新值newValue
2fill_n()将从beg开始的前num个元素赋予新值newValue
3调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
4时间复杂度:线性

void generate (ForwardIterator beg, ForwardIterator end, Func op);
void generator_n (OutputIterator beg, Size num, Func op);
1generate()调用op产生新值并赋给区间[beg, end)内的每一个元素
2generate_n()调用op产生新值并赋给以beg开始的区间内的前num个元素
3调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
4时间复杂度:线性

(12)替换元素算法:
void replace (ForwardIterator beg, ForwardIterator end, const T& oldValue, const T& newValue);
void replace_if (ForwardIterator beg, ForwardIterator end, UnaryPredicate op, const T& newValuedValue);
1replace()将区间[beg, end)内每一个与oldValue相等的元素替换为newValue
2replace_if()将区间[beg ,end)内每一个令op(elem)为true的元素替换为newValue
3op不应该在函数调用过程中改变自身状态
4时间复杂度:线性

OutputIterator replace_copy (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, const T& oldValue, const T& newValue);
OutputIterator replace_copy_if (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, UnaryPredicate op, const T& newValue);
1replace_copy()是copy()和replace()的组合,它将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg开始的目标区间去,同时将与oldValue相等的所有元素替换成newValue
2replace_copy_if()是copy()和replace_if()的组合,它将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg开始的目标区间去,同时将令op(elem)结果为true的所有元素替换成newValue
3俩个算法都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4op不应该在函数调用过程中改变自身状态
5时间复杂度:线性

(13)移除性算法:
ForwardIterator remove (ForwardIterator beg, ForwardIterator end, const T& value);
ForwardIterator remove_if (ForwardIterator beg, ForwardIterator end, UnaryPredicate op);
1remove()会移除区间[beg, end)中的每一个与value相等的元素
2remove_if()会移除区间[beg, end)中的每一个令op(elem)结果为true的元素
3两个算法都会返回变动后的序列的新逻辑终点(也就是最后一个未被移除元素的下一个位置)
4这些算法会把原来置于后面的未被移除元素向前移动,覆盖被移除元素
5未被移除元素在相对次序上保持不变
6调用者在调用此算法后,应保证从此采用返回的新逻辑终点而不再使用原始终点end
7op不应该在函数调用过程中改变自身状态
8由于会发生元素变动,所以这些算法不可用于关联式容器,关联式容器提供了功能相似的成员函数erase()
9list提供了一个等效成员函数remove():不是重新赋值元素,而是重新安排指针
10时间复杂度:线性

OutputIterator remove_copy (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, const T& value);
OutputIterator remove_copy_if (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, UnaryPredicate op);
1remove_copy()是copy()和remove()的组合,它将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg开始的目标区间去,同时移除与value相等的所有元素
2remove_copy_if()是copy()和remove_if()的组合,它将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg开始的目标区间去,同时移除令op(elem)结果为true的所有元素
3俩个算法都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4op不应该在函数调用过程中改变自身状态
5调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
6时间复杂度:线性

ForwardIterator unique (ForwardIterator beg, ForwardIterator end);
ForwardIterator unique (ForwardIterator beg, ForwardIterator end, BinaryPredicate op);
1两个算法都会移除连续重复元素中的多余元素
2第一形式将区间[beg, end)内的所有与前一个元素相等的元素移除,所以源区间必须先经过排序,才能使用这个算法
3第二形式将每一个“位于元素e之后并且造成op(elem ,e)结果为true”的所有elem元素移除,换言之此op并非用来将元素和其原本的前一元素比较,而是将它和未被移除的前一元素比较
4两种形式都返回被变动后的序列的新终点(最后一个未被移除的元素的下一个位置)
5两个算法将原本位置在后的未被移除元素向前移动,覆盖被移除元素
6未被移除元素在相对次序上保持不变
7调用者在调用此算法后,应保证从此采用返回的新逻辑终点而不再使用原始终点end
8op不应该在函数调用过程中改变自身状态
9由于会发生元素变动,所以这些算法不可用于关联式容器
10list提供了一个等效成员函数unique():不是重新赋值元素,而是重新安排指针
11时间复杂度:线性

OutputIterator unique_copy (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
OutputIterator unique_copy (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, BinaryPredicate op);
1两种形式都是copy()和unique()的组合
2两者都将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg开始的目标区间去,并移除重复元素
3俩个算法都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
5时间复杂度:线性

(14)变序性算法:
void reverse (BidirectionalIterator beg, BidirectionalIterator end);
OutputIterator reverse_copy (BidirectionalIterator sourceBeg, BidirectionalIterator sourceEnd, OutputIterator destBeg);
1reverse()将区间[beg, end)内的元素全部逆序
2reverse_copy()会将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg起始的目标区间,并在复制过程中颠倒安置次序
3reverse_copy()返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
5list提供了一个等效成员函数reverse():不是重新赋值元素,而是重新安排指针
6时间复杂度:线性

void rotate (ForwardIterator beg, ForwardIterator newBeg, ForwardIterator end);
1将区间[beg, end)内的元素进行旋转,执行后*newBeg成为新的第一元素
2调用者必须保证newBeg是区间[beg, end)内的一个有效位置,否则会引发未定义的行为
3时间复杂度:线性

void rotate_copy (ForwardIterator sourceBeg, ForwardIterator newBeg, ForwardIterator sourceEnd, OutputIterator destBeg);
1这是rotate()和copy()的组合
2将源区间[sourceBeg, sourceEnd)内的元素复制到以destBeg起始的目标区间中,同时旋转元素使*newBeg成为新的第一元素
3返回目标区间内最后一个被复制的元素的下一个位置
4调用者必须保证newBeg是区间[sourceBeg, sourceEnd)内的一个有效位置,否则会引发未定义的行为
5调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
6源区间和目标区间不可重叠
7时间复杂度:线性

bool next_permutation (BidirectionalIterator beg, BidirectionalIterator end);
bool prev_permutation (BidirectionalIterator beg, BidirectionalIterator end);
1next_permutation()会改变区间[beg, end)内的元素次序,使它符合“下一个排列次序”
2prev_permutation()会改变区间[beg, end)内的元素次序,使它符合“上一个排列次序”
3如果元素得以排列成“正规”次序,则两个算法都返回true。所谓正规次序,对next_permutation()而言为升序,对prev_permutation()而言为降序。因此如果要走遍所有排序,你必须先将所有元素(按升序或降序)排序,然后开始以循环方式调用prev_permutation()或next_permutation()直到算法返回false
4时间复杂度:线性

void random_shuffle (RandomAccessIterator beg, RandomAccessIterator end);
void random_shuffle (RandomAccessIterator beg, RandomAccessIterator end, RandomFunc& op);
1第一形式使用一个均匀分布随机数产生器来打乱区间[beg, end)内的元素次序
2第二形式使用op来打乱区间[beg, end)内的元素次序。算法内部会使用一个整数值来调用op:op(max),它应该返回一个大于零而小于max的随机数但不包括max自身
3注意op是一个non-const reference,所有你不可以将暂时数值或一般函数传进去
4时间复杂度:线性

BidirectionalIterator partition (BidirectionalIterator beg, BidirectionalIterator end, UnaryPredicate op);
BidirectionalIterator stable_partition (BidirectionalIterator beg, BidirectionalIterator end, UnaryPredicate op);
1两种算法将区间[beg, end)中的“造成op(elem)结果为true”的元素向前端移动
2两种算法都返回“令op(elem)结果为false”的第一个元素位置
3两者差别为无论元素是否符合给定的准则,stable_partition()会保持它们之间的相对次序
4你可以运用此算法根据排序准则将所有元素分割为两部分,nth_element()具有类似能力
5op不应该在函数调用中改变自身状态
6时间复杂度:partition()为线性,stable_partition()当系统有足够的内存时为线性、不足时为O(nlgn)

(15)排序算法:
void sort (RandomAccessIterator beg, RandomAccessIterator end);
void sort (RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
void stable_sort (RandomAccessIterator beg, RandomAccessIterator end);
void stable_sort (RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
1sort()和stable_sort()的上述第一形式使用operator<对区间[beg, end)内的所有元素进行排序
2sort()和stable_sort()的上述第二形式使用op(elem1, elem2)作为排序准则对区间[beg, end)内的所有元素进行排序
3op不应该在函数调用中改变自身状态
4sort()和stable_sort()的区别是后者保证相等元素的原本相对次序在排序后保持不变
5不可以对list调用这些算法,因为list不支持随机存取迭代器不过list提供了一个成员函数sort()
6时间复杂度:sort():O(nlgn),stable_sort()当系统有足够的内存时为O(nlgn)、不足时为O(nlgn*lgn)

void partial_sort (RandomAccessIterator beg, RandomAccessIterator sortEnd, RandomAccessIterator end);
void partial_sort (RandomAccessIterator beg, RandomAccessIterator sortEnd, RandomAccessIterator end, BinaryPredicate op);
1上述第一形式使用operator<对区间[beg, end)内的所有元素进行排序,使区间[beg, sortEnd)内的元素处于有序状态
2上述第二形式使用op(elem1, elem2)作为排序准则对区间[beg, end)内的所有元素进行排序,使区间[beg, sortEnd)内的元素处于有序状态
3op不应该在函数调用中改变自身状态
4和sort()不同的是partial_sort()并不对全部元素进行排序:一旦第一个元素直至sortEnd之间的所有元素都排好次序就立刻停止,不会对剩余的元素进行排序
5如果end和sortEnd相等,那么partial_sort()会对整个序列进行排序,平均而言其效率不及sort(),不过最差情况而言优于sort()
6时间复杂度:线性和O(nlgn)之间

RandomAccessIterator partial_sort_copy (InputIterator sourceBeg, InputIterator sourceEnd, RandomAccessIterator destBeg, RandomAccessIterator destEnd);
RandomAccessIterator partial_sort_copy (InputIterator sourceBeg, InputIterator sourceEnd, RandomAccessIterator destBeg, RandomAccessIterator destEnd, BinaryPredicate op);
1两者都是copy()和partial_sort()的组合
2它们将元素从源区间[sourceBeg, sourceEnd)复制到目标区间[destBeg, destEnd)同时排序
3被排序元素的数量是源区间和目标区间两者所含元素数量的最小值
4两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
5时间复杂度:线性和O(nlgn)之间

void nth_element (RandomAccessIterator beg, RandomAccessIterator nth, RandomAccessIterator end);
void nth_element (RandomAccessIterator beg, RandomAccessIterator nth, RandomAccessIterator end, BinaryPredicate op);
1两种形式都对区间[beg, end)内的元素进行排序,使第n个位置上的元素就位,也就是说所有在位置n之前的元素小于等于它,所有位置在n之后的元素都大于等于它。这样你就得到了根据n位置上的元素分割开来的两个子序列,第一子序列的元素统统小于第二子序列的元素。如果你只需要n个最大或最小的元素,但不要求它们必须已序,那么这个算法就很有用。
2上述第一形式使用operator<作为排序准则
3上述第二形式使用op(elem1, elem2)作为排序准则
4op不应该在函数调用中改变自身状态
5时间复杂度:线性

(16)Heap算法:
void make_heap (RandomAccessIterator beg, RandomAccessIterator end);
void make_heap (RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
1两种形式都将[beg, end)内的元素转化为heap
2第二形式将op(elem1, elem2)视为排序准则
3只有在多于一个元素的情况下才有必要使用这些函数来处理heap
4时间复杂度:线性

void push_heap (RandomAccessIterator beg, RandomAccessIterator end);
void push_heap (RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
1两种形式都将end之前的最后一个元素加入原本就是个heap的[beg, end-1)区间内使整个区间[beg, end)成为一个heap
2第二形式将op(elem1, elem2)视为排序准则
3调用者必须保证进入函数时,区间[beg, end-1)内的元素原本已形成一个heap,而新元素紧跟其后
4时间复杂度:对数

void pop_heap (RandomAccessIterator beg, RandomAccessIterator end);
void pop_heap (RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
1以上两种形式都将heap[beg, end)内的最高元素也就是第一个元素移动到最后的位置上,并将剩余区间[beg, end-1)内的元素组织起来成为一个新heap
2第二形式将op(elem1, elem2)视为排序准则
3调用者必须保证进入函数时,区间[beg, end)内的元素原本已形成一个heap,而新元素紧跟其后
4时间复杂度:对数

void sort_heap (RandomAccessIterator beg, RandomAccessIterator end);
void sort_heap (RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
1以上两种形式都将heap[beg, end)转换为一个已序序列
2第二形式将op(elem1, elem2)视为排序准则
3此算法一结束,该区间就不再是个heap了
4调用者必须保证进入函数时,区间[beg, end)内的元素原本已形成一个heap,而新元素紧跟其后
5时间复杂度:对数

(17)搜寻元素:
bool binary_search (ForwardIterator beg, ForwardIterator end, const T& value);
bool binary_search (ForwardIterator beg, ForwardIterator end, const T& value, BinaryPredicate op);
1两种形式都用来判断已序区间[beg, end)中是否含有和value等值的元素
2第二形式将op(elem1, elem2)视为排序准则
3如果想获得被搜寻元素的位置,应使用lower_bound(),upper_bound()或equal_range()算法
4调用者必须保证进入算法之际该区间已序
5时间复杂度:如果搭配随机存取迭代器则为对数复杂度,否则为线性

bool includes (InputIterator1 beg, InputIterator1 end, InputIterator2 searchBeg, InputIterator2 searchEnd);
bool includes (InputIterator1 beg, InputIterator1 end, InputIterator2 searchBeg, InputIterator2 searchEnd, BinaryPredicate op);
1两种形式都用来判断已序区间[beg, end)是否包含另一个已序区间[searchBeg, searchEnd)中的每一个元素。也就是说对于[searchBeg, searchEnd)中的每一个元素,如果[beg, end)必有一个对应的相等元素那么[searchBeg, searchEnd)肯定是[beg, end)的子集
2第二形式将op(elem1, elem2)视为排序准则
3调用者必须保证在进入算法之际两区间都应该已经按照相同的排序准则排好序了
4时间复杂度:线性

ForwardIterator lower_bound (ForwardIterator beg, ForwardIterator end, const T& value);
ForwardIterator lower_bound (ForwardIterator beg, ForwardIterator end, const T& value, BinaryPredicate op);

ForwardIterator upper_bound (ForwardIterator beg, ForwardIterator end, const T& value);
ForwardIterator upper_bound (ForwardIterator beg, ForwardIterator end, const T& value, BinaryPredicate op);
1lower_bound()返回第一个“大于等于value”的元素位置,这是可插入“元素值为value”且“不破坏区间[beg, end)已序性”的第一个位置
2upper_bound()返回第一个“大于value”的元素位置,这是可插入“元素值为value”且“不破坏区间[beg, end)已序性”的最后一个位置
3如果不存在其值为value的元素,上述算法都返回end
4op(elem1, elem2)视为排序准则
5调用者必须保证在进入算法之际所有区间都应该已经按照排序准则排好序了
6如果要同时获得lower_bound()和upper_bound()的结果,请使用equal_range()
7关联式容器分别提供等效成员函数,性能更好
8时间复杂度:如果搭配随机存取迭代器则为对数复杂度,否则为线性

pair<ForwardIterator, ForwardIterator> equal_range (ForwardIterator beg, ForwardIterator end, const T& value);
pair<ForwardIterator, ForwardIterator> equal_range (ForwardIterator beg, ForwardIterator end, const T& value, BinaryPredicate op);
1两种形式都返回与value相等的元素所形成的区间,在此区间内插入其值为value的元素并不会破坏区间[beg, end)的已序性
2和下式等效:make_pair(lower_bound(……), upper_bound(……))
3第二形式将op(elem1, elem2)视为排序准则
4调用者必须保证在进入算法之际两区间都应该已经按照相同的排序准则排好序了
5关联式容器分别提供等效成员函数,性能更好
6时间复杂度:如果搭配随机存取迭代器则为对数复杂度,否则为线性

(18)合并元素:
OutputIterator merge (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator merge (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
1两者都将源区间[source1Beg, source1End)和[source2Beg, source2End)内的元素合并,使得以destBeg起始的目标区间内含两个源区间的所有元素
2目标区间内的所有元素都将按顺序排列
3两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4第二形式将op(elem1, elem2)视为排序准则
5源区间没有任何变化
6调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
7list提供了一个等效成员函数merge()
8根据标准调用者应当确保两个源区间一开始都是已序,然而在大部分实作版本中上述算法可以将两个无序的源区间内的元素合并到一个无序的目标区间中,不过要考虑到这样的移植性
9目标区间和源区间不得重叠
10如果你要确保两个源区间中都存在的元素在目标区间中只出现一次,请使用set_union()
11如果你要获得同时存在于两个源区间的所有元素,请使用set_intersection()
12时间复杂度:线性

OutputIterator set_union (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator set_union (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
1两者都将源区间[source1Beg, source1End)和[source2Beg, source2End)内的元素合并,得到以destBeg起始的目标区间——这个区间内含的元素要不来自第一源区间,要不就来自第二源区间,或是同时来自两个区间
2同时出现于两个源区间内的元素在并集区间中将只出现一次。不过如果原来的某个源区间内原本就存在重复元素,则目标区间也会有重复元素,重复的个数是两个源区间内的重复个数的较大值
3两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4第二形式将op(elem1, elem2)视为排序准则
5源区间没有任何变化
6调用者应当确保两个源区间一开始都是已序
7调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
8目标区间和源区间不得重叠
9若想得到两个源区间的全部元素,应使用merge()
10时间复杂度:线性
11目标区间内的所有元素都按顺序排列

OutputIterator set_intersection (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator set_intersection (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
1两者都将源区间[source1Beg, source1End)和[source2Beg, source2End)内的元素合并,得到以destBeg起始的目标区间——这个区间内含的元素不但存在于第一源区间,也存在于第二源区间
2如果原来的某个源区间内原本就存在重复元素,则目标区间也会有重复元素,重复的个数是两个源区间内的重复个数的较小值
3两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
4第二形式将op(elem1, elem2)视为排序准则
5源区间没有任何变化
6调用者应当确保两个源区间一开始都是已序
7调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
8目标区间和源区间不得重叠
9目标区间内的所有元素都按顺序排列
10时间复杂度:线性

OutputIterator set_difference (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator set_difference (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
1两者都将源区间[source1Beg, source1End)和[source2Beg, source2End)内的元素合并,得到以destBeg起始的目标区间——这个区间内含的元素只存在于第一源区间,不存在于第二源区间
2目标区间内的所有元素都按顺序排列
3如果原来的某个源区间内原本就存在重复元素,则目标区间也会有重复元素,重复的个数是第一源区间内的重复个数减去第二源区间内的相应重复个数,如果第二源区间内的重复个数大于第一源区间内的相应重复个数,则目标区间内的对应重复个数将会是零
4两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
5第二形式将op(elem1, elem2)视为排序准则
6源区间没有任何变化
7调用者应当确保两个源区间一开始都是已序
8调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
9目标区间和源区间不得重叠
10时间复杂度:线性

OutputIterator set_symmetric_difference (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator set_symmetric_difference (InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
1两者都将源区间[source1Beg, source1End)和[source2Beg, source2End)内的元素合并,得到以destBeg起始的目标区间——这个区间内含的元素或存在于第一源区间,或存在于第二源区间,但不同时存在于两个源区间
2目标区间内的所有元素都按顺序排列
3如果原来的某个源区间内原本就存在重复元素,则目标区间也会有重复元素,重复的个数是两个源区间内的对应重复元素的个数差值
4两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
5第二形式将op(elem1, elem2)视为排序准则
6源区间没有任何变化
7调用者应当确保两个源区间一开始都是已序
8调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
9目标区间和源区间不得重叠
10时间复杂度:线性

void inplace_merge (BidirectionalIterator beg1, BidirectionalIterator end1beg2, BidirectionalIterator end2);
void inplace_merge (BidirectionalIterator beg1, BidirectionalIterator end1beg2, BidirectionalIterator end2, BinaryPredicate op);
1两者都是将已源区间[beg1, end1beg2)和[end1beg2, end2)的元素合并,使区间[beg1, end2)成为两者之总和(且形成已序)
2时间复杂度:内存足够为线性否则为O(nlgn)

(19)数值算法:
运用数值算法需要包含头文件:#include<numeric>

T accumulate (InputIterator beg, InputIterator end, T initValue);
T accumulate (InputIterator beg, InputIterator end, T initValue, BinaryFunc op);
1第一形式计算initValue和区间[beg, end)内的所有元素总和,具体地说它针对每一个元素调用initValue+=elem
2第二形式计算initValue和区间[beg, end)内每一个元素进行op运算的结果,具体地说它针对每一个元素调用initValue=op(initValue, elem)
3如果序列为空则两者都返回initValue
4时间复杂度:线性

T inner_product (InputIterator1 beg1, InputIterator1 end1,InputIterator2 beg2, T initValue);
T inner_product (InputIterator1 beg1, InputIterator1 end1,InputIterator2 beg2, T initValue, BinaryFunc op1, BinaryFunc op2);
1第一形式计算并返回[beg1, end1)区间和以beg2为起始的区间的对应元素组(再加上initValue)的内积。具体地说针对两区间内的每一组对应元素调用initValue=initValue+elem1*elem2
2第二形式将[beg1, end1)区间和以beg2为起始的区间的对应元素组进行op2运算再和initValue进行op1运算并将结果返回。具体地说针对两区间内的每一组对应元素调用initValue=op1(initValue, op2(elem1, elem2))
3如果第一区间为空则两者都返回initValue
4调用者必须保证以beg2为起始的区间内含足够元素空间
5op1和op2都不得变动其参数内容
6时间复杂度:线性

OutputIterator partial_sum (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
OutputIterator partial_sum (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, BinaryFunc op);
1第一形式计算源区间[sourceBeg, sourceEnd)中的每个元素的部分和,然后将结果写入以destBeg为起始的区间
2第二形式计算源区间[sourceBeg, sourceEnd)中的每个元素和其先前所有元素进行op运算,然后将结果写入以destBeg为起始的区间
3对于数列a1 a2 a3 ……它们分别计算a1, a1+a2, a1+a2+a3,……和a1, a1 op a2, a1 op a2 op a3,……
4 两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
5第一形式相当于把一个相对值序列转换为一个绝对值序列,就此而言partial_sum()正好和adjacent_difference()互补
6源区间和目标区间可以相同
7调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
8op不得变动其参数内容
9时间复杂度:线性

OutputIterator adjacent_difference (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
OutputIterator adjacent_difference (InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, BinaryFunc op);
1第一形式计算源区间[sourceBeg, sourceEnd)中的每个元素和其紧邻前驱元素的差值,然后将结果写入以destBeg为起始的区间
2第二形式计算源区间[sourceBeg, sourceEnd)中的每个元素和其紧邻前驱元素进行op运算,然后将结果写入以destBeg为起始的区间
3第一个元素只是被很单纯的加以复制
4对于数列a1 a2 a3 a4……它们分别计算a1, a2-a1, a3-a2,a4-a3, ……和a1, a2 op a1, a3 op a2, a4 op a3,……
5 两者都返回目标区间内最后一个被复制的元素的下一个位置,也就是第一个未被覆盖的元素的位置
6第一形式相当于把一个绝对值序列转换为一个相对值序列,就此而言partial_sum()正好和adjacent_difference()互补
7源区间和目标区间可以相同
8调用者必须保证目标区间有足够的空间,否则就得使用insert迭代器
9op不得变动其参数内容
10时间复杂度:线性

尾词_if:如果算法有两种形式,参数个数都相同,但第一形式的参数要求传递一个值,第二形式的参数要求传递一个函数或仿函数,那么尾词_if就派上了用场,无尾词的那个要求传递数值,有尾词的那个要求传递函数或仿函数。不过并非所有“要求传递仿函数”的算法都有尾词_if,如果算法以额外参数来接受这样的函数或仿函数,那么不同版本的算法就可以采用相同的命名。
尾词_copy:这个尾词用来表示在此算法中,元素不光被操作,还会被复制到目标区间。

感谢老司机博文中的分析,我做了补充和修改,原始博文http://www.cnblogs.com/zxh1210603696/p/3264992.html

“If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime.”
原文地址:https://www.cnblogs.com/Scorpio989/p/4331224.html