泛型算法只是依赖于迭代器的操作,而不是依赖于容器
泛型算法可以分为3大类:
下面的vec和vec2代表相同类型的容器
1.只读算法:只允许读取其输入范围内的元素,而不改变元素
find(vec.cbegin(), vec.cend(), k)
查找算法:前两个参数表示元素范围的迭代器,第三个参数k表示要查找的元素,查找成功则返回等于第一个元素的迭代器,查找失败返回尾后指针
accumulate(vec.cbegin(), vec.cend(), 0)
求和算法:前两个参数表示元素范围的迭代器,第三个参数表示和的初始值,返回该类型的参数范围内的和,可以为int,string等
equal(vec.cbegin(), vec.cend(), vec2.cbegin() )
比较算法:将第一个范围内的元素和第二个序列中的元素比较,如果对应元素都相等,返回true,否则返回false,这里默认第二个序列的元素数>=第一个范围内的元素数
2.写容器元素算法:将元素写入输入范围
fill(vec.cbegin(), vec.cend(), 0)
表示迭代器范围内的值都被置为0(假设vec存的是int型)
fill_n(vec.begin(), vec.size(), 0)
表示从指定迭代器 vec.begin() 开始以后的vec.size()个元素的值都被置为0(假设vec存的是int型)
注:上面的写算法不允许在空容器上调用,即容器中有几个元素,写算法才能写几个元素,只能修改,不能添加,如果想要添加只能使用插入迭代器(下篇会介绍)
copy(vec.cbegin(), vec.cend(), vec2.cbegin())
拷贝算法:将迭代器范围内的元素拷贝到vec2容器中,这里默认第二个容器的空间能够存储该迭代器范围内的元素
replace(vec.cbegin(), vec.cend(), before, after)
替换算法:将容器迭代器范围内的元素中 所有为before的元素替换为after的元素,before和after分别为存储类型的具体数值
replace_copy(vec.cbegin(), vec.cend(), back_inserter(vec2), before, after)
替换算法:将容器迭代器范围内的元素中 所有为before的元素替换为after的元素,并插入到vec2中,before和after分别为存储类型的具体数值
3.重排容器元素算法
sort(vec.cbegin(), vec.cend())
排序算法:将迭代器范围内的元素按照定义的“<”来进行排序
unique(vec.cbegin(), vec.cend())
排序算法:将迭代器范围内的元素按照unique的标准库算法进行排序,使得不重复的元素出现在开始的位置,并且返回一个指向最后一个不重复元素之后的迭代器
注:要真正删除容器中的元素,必须使用容器操作,泛型算法只是依赖于迭代器的,向容器中插入元素可以不必使用容器操作,可以使用插入迭代器操作。
最全面的STL泛型算法总结:
当前的STL一共有85个通用算法,这些算法可以使用在所有的STL容器上。有的容器拥有与通用算法函数相同功能的成员函数,则优先使用成员函数版本。
所有的这些通用算法在这里可以查询得到。
这些通用算法的参数 和 返回值一般都有迭代器(通过迭代器,将算法与数据结构解耦),用来表示元素在容器中的位置(前后两个迭代器,组成一个左闭右开的区间)。
一、非修改型算法
函数名 | 参数 | 功能 |
---|---|---|
1、 | all_of() | 区间 + 一元谓词 判断区间中所有元素是否都满足谓词条件。 |
2、 | any_of() | 区间 + 一元谓词 判断区间中是否有一个元素满足谓词条件。 |
3、 | none_of() | 区间 + 一元谓词 判断区间中的元素是否都不满足谓词条件。(全部都不满足的否定是至少有一个满足,none_of() 和 any_of() 的结果是对立的)。 |
4、 | for_each() | 区间 + 一元可调用对象 对每个元素都执行该一元操作,注意函数的返回值是该一元操作对象,需要注意当一元操作对象是有状态的情况。 |
5、 | find() | 区间 + 值 寻找值第一次在区间中出现的位置。 |
6、 | find_if() | 区间 + 一元谓词 寻找区间中第一次满足谓词条件的位置。 |
7、 | find_if_not() | 区间 + 一元谓词 寻找区间中第一次不满足条件的位置。 |
8、 | find_end() | 区间1 + 区间2 + 【二元谓词】通常的STL的算法的函数的名称都是 见文知意 的,这个find_end() 其实名称应该是search_end() , 用来匹配大区间中最后一次出现和子区间对应元素满足条件二元谓词条件的位置,默认是 operator= 来判断相等。 |
9、 | find_first_of() | 区间1 + 区间2 +【二元谓词】 判断区间1中第一次某个元素和区间2中的任意一个元素满足二元谓词条件的位置,默认是operator= 判断相等。(找到第一个满足二元谓词的元素的位置) |
10、 | adjacent_find() | 区间 + 【二元谓词】 寻找第一个和其后的元素满足二元条件的位置,默认是operator= 寻找第一次相邻元素相等的位置。(寻找相邻元素相等的第一个位置) |
11、 | count() | 区间 + 值 统计值在区间中出现的次数。 |
12、 | count_if() | 区间 + 【一元谓词】 统计区间中满足条件的元素的个数。 |
13、 | mismatch | 区间1 + 区间2起始 + 【二元谓词】 以pari 的形式,返回区间1 和 区间2 中对应元素不满足条件的两个位置,默认是operator= 返回两区间元素不相等的两个位置。(返回对应位置的元素不相等的位置) |
14、 | equal() | 区间1 + 区间2起始 + 【二元谓词】 判断区间1 和 区间2中对应元素是否都满足条件(区间2元素可以更多),默认是operator= 判断对应位置是否相等。(返回对应位置的元素相等的位置) |
15、 | is_permutation() | 区间1 + 区间2起始 + 【二元谓词】 判断区间1是否经过某种全排列和区间2的对应元素满足二元谓词条件,默认条件是operator= 判断相等(区间2的元素可以多于区间1)。(判断两个序列是否为同一元素集的不同排列!,元素都相同(可以存在重复元素),只是顺序不同) |
16、 | search() | 区间1 + 区间2 + 【二元谓词】 同find_end() 用来匹配第一次区间1对应元素和区间2满足条件的位置。 |
17、 | search_n() | 区间 + n个值的个数 + 值 + 【二元谓词】 寻找连续n个元素和值组成的n个二元组满足二元谓词的,元素作为二元谓词的第一个参数,值为第二个参数。 |
有后缀if 的表示需要一个条件,
二、修改型算法
返回的位置表示修改过和非修改过的界线,或者在目的区间中的结束位置。
函数名 | 参数 | 功能 |
---|---|---|
18、 | copy() | 区间1 + 区间2一个位置 将区间1中的元素拷贝到2中,返回拷贝到2中的结束位置。 |
19、 | copy_n() | 区间1起始 + 元素个数n + 区间2一个位置 将区间1中前 n 个元素拷贝到区间2,从2中的该位置往前拷贝。(注意迭代器的插入语意和覆盖语意),返回在2中的结束位置。 |
20、 | copy_if() | 区间1 + 区间2一个位置 + 【一元谓词】 将区间1中满足条件的元素拷贝到2中,返回在2中的结束位置。 |
21、 | copy_backward() | 区间1 + 区间2一个位置 从后向前,将区间1中满足 条件的元素拷贝到2中,范围在2中的结束位置。 |
22、 | move() | 区间1 + 区间2一个位置 窃取区间1中的元素的资源,移动构造新的元素放到区间2当中。注意move(container) 是窃取整个容器的资源,而不是每个元素。返回在2中的结束位置。 |
23、 | move_backward() | 区间1 + 区间2一个位置 从后向前,窃取区间1中元素的资源来构造新的元素放到区间2当中。返回在2中的结束位置。 |
24、 | swap() | 变量1 + 变量2 交换两个变量的值。 |
25、 | swap_ranges() | 区间1 + 区间2一个位置 交换两个区间的对应元素。返回在2中的结束位置(也就是没有交换的那个位置)。 |
26、 | iter_swap() | 迭代器1 + 迭代器2 交换两个迭代器所指的元素。 |
27、 | transform() | 区间1 + 区间2一个位置 + 一元可调用对象 将区间1中的元素进过变换,放到2中,返回区间2中结束的位置。或者 区间1 + 区间2起始 + 区间3一位置 + 二元可调用对象 将区间1和区间2对应位置组成的二元组变换之后,放到区间3当中,返回区间3中结束的位置。 |
28、 | replace() | 区间 + 旧值 + 新值 将区间中的所有旧值替换为新值。 |
29、 | replace_if() | 区间 + 一元谓词 + 新值 将区间中所有满足条件的元素替换为新的值。 |
30、 | replace_copy() | 区间1 + 区间2起始 + 旧值 + 新值 将区间中所有旧值替换为新值,然后将整个区间拷贝到2中。返回2中的结束位置。 |
31、 | replace_copy_if() | 区间1 + 区间2起始 + 一元谓词 + 新值 将区间1中所有满足条件的元素替换为新值,然后拷贝到2中,返回值为2中的结束。 |
32、 | fill() | 区间 + 值 将区间填充为该值。 |
33、 | fill_n() | 区间起始 + 个数n + 值 从起始位置开始填充n 个该值。 |
34、 | generate() | 区间 + 0元可调用对象 为区间生成值。 |
35、 | generate_n() | 区间 + 个数n + 值 从起始位置开始产生n 个值。 |
36、 | remove() | 区间 + 值 将该值得元素移除,注意这里并非真的移除,而只是被覆盖掉,返回一个分界,需要和成员函数 .erase搭配使用。 |
37、 | remove_if() | 区间 + 一元谓词 将满足条件的元素移除,返回移除之后新的结束。真的移除需要和成员函数.erase() 搭配使用。 |
38、 | remove_copy() | 区间1 + 区间2一个位置 + 值 将不等于该值的元素拷贝到2当中,返回2中结束的位置。 |
39、 | remove_copy_if() | 区间1 + 区间位置2 + 一元谓词 将区间1中满足条件的元素拷贝到2当中。 |
40、 | unique() | 区间 + 【二元谓词】 只保留连续满足条件的元素的第一个,默认是判断前后相等,返回值为一个分界,分界前边是剩下需要的元素,需要和 .erase()搭配使用。(只判断前后元素是否重复,重复的话,只保留一个元素;要想对无序的容器进行去重,需要先sort再unique) |
41、 | unique_copy() | 区间1 + 区间2一个位置 + 【二元谓词】只保留前后连续满足二元谓词条件的第一个,然后拷贝到区间2 当中,返回2 中的结束位置。 |
42、 | reverse() | 区间 将区间中的元素逆序。 |
43、 | reverse_copy() | 区间1 + 区间2一个位置 将区间1中的元素以逆序拷贝到区间2当中。 |
44、 | rotate() | 区间起始 + 区间中位值 + 区间结束 将区间起始和区间中位值构成的子区间移动到末尾,实现循环右移。相反,使用该函数也可以实现循环左移。 |
45、 | rotate_copy() | 区间1起始 + 区间1中位值 + 区间1结束 + 区间2一个位置 将区间1循环右移的结果放到区间2当中。 |
46、 | random_shuffle() | 区间 + 【随机数生成器】 将区间中的元素随机乱序。(随机数生成器是可选参数。) |
47、 | shuffle() | 区间 + 生成器 将区间中的元素随机乱序。 |
三、二分割算法
函数名 | 参数 | 功能 |
---|---|---|
48、 | is_partitioned() | 区间 + 一元谓词 判断区间时候前边一部分元素满足条件,后边的部分不满足条件。(如果所有的都满足,一样返回值为true)。 |
49、 | partition() | 区间 + 一元谓词 (将区间依据谓词分成两部分)是区间前边一部分元素满足条件,后边一部分元素不满足条件。返回值为不满足的那部分的起始位置。 |
50、 | stable_partition() | 区间 + 一元谓词 稳定的分隔为两部分(相等元素的相对位置不变,返回值为分界位置。) |
51、 | partition_copy() | 区间1 + 区间2一位置 + 区间3一位置 + 一元谓词 , 将区间1中满足条件的元素放到2当中,不满足条件的元素放到3当中。以pair 的形式返回2,3中的结束位置。 |
52、 | partition_point() | 区间 + 一元谓词 对于一个已经分割开的区间,返回分界的位置。 |
四、排序算法
默认下,二元比较谓词为less<>() , 即升序排列.
函数名 | 参数 | 功能 |
---|---|---|
53、 | sort() | 区间 + 【二元比较谓词】 |
54、 | stable_sort() | 区间 + 【二元比较谓词】 稳定排序。 |
55、 | partial_sort() | 区间起始first + 区间中位置mid + 区间结束last + 【二元比较谓词】 部分排序,使first 和 mid构成的区间是整个区间的最小(大)值的升序。 |
56、 | partial_sort_copy() | 区间1 + 区间2起始 + 区间2中位置 + 【二元比较谓词】 将区间1中最小(大)的区间2子区间可容纳的元素的个数的元素放到2 当中,返回值仍然是区间2中的结束位置,实际上就是第四个参数。 |
57、 | is_sorted() | 区间 + 【二元比较谓词】 判断区间是否已经是排好序的。 |
58、 | is_sorted_until() | 区间 + 【二元比较谓词】 返回第一个不是正确顺序的元素的位置。 |
59、 | nth_element() | 区间起始 + 区间中位置+ 区间结束 使区间中位置的值恰好是排好序的该位置的值。 |
五、二分查找
既然是二分查找,就要求区间事先必须是有序的,就是经过排序的或者是map,set等有序容器(不过map,set的有自己的成员查找函数)。
函数名 | 参数 | 功能 |
---|---|---|
60、 | lower_bound() | 区间 + 值 +【二元比较谓词】 返回值第一次出现的那个位置,如果没有出现,则是返回值插入到该位置,仍然有序的那个位置。 |
61、 | upper_bound() | 区间 + 值 + 【二元比较谓词】 返回适合插入的位置,使插入之后仍然有序。 |
62、 | equal_range() | 区间 + 值 + 【二元比较谓词】 以pair 的形式返回lower_bound() 和 upper_bound() 的结果。 |
63、 | binary_search() | 区间 + 值 + 【二元比较谓词】 找到返回true, 没有找到返回false |
六、归并操作
函数名 | 参数 | 功能 |
---|---|---|
64、 | merge() | 区间1 + 区间2 + 区间3一位置输出+ 【二元比较谓词】 既然是归并,肯定要有序才行,合成一个仍然是有序的放到区间3中,返回值为区间3中的结束位置。 |
65、 | inplace_merge() | 区间起始 + 区间中位置 + 区间结束 + 【二元比较谓词】 区间的前后两部分都是有序的,将前后两部分的归并。 |
66、 | includes() | 区间1 + 区间2 + 【二元比较谓词】 判断区间1是否全部包含区间2中的元素。 |
67、 | set_union() | 区间1 + 区间2 + 区间3一位置 + 【二元谓词】 求两个有序区间的并集元素放到区间3 当中,默认的二元谓词用来判断相等。 |
68、 | set_intersection() | 区间1 + 区间2 + 区间3一位置 + 【二元谓词】 求两个有序区间的交集元素放到区间3当中,默认的二元谓词用来判断相等。 |
69、 | set_difference() | 区间1 + 区间2 + 区间3一位置 + 【二元谓词】 求两个有序区间的差集元素放到区间3当中,默认的二元谓词用来判断相等。 |
70、 | set_symmetric_difference() | 区间1 + 区间2 + 区间3一位置 + 【二元谓词】 求两个有序区间的对称差集(即并集与交集的差集)放到区间3当中,默认判断相等。 |
七、堆操作
默认的,堆操作的二元比较操作是less<>(), 这样构成的堆是最大堆(通过从最后一个非叶子节点的上浮操作,用到的比较操作符是less),关于堆,见这里。
函数名 | 参数 | 功能 |
---|---|---|
71、 | push_heap() | 区间 + 【二元比较谓词】 对一个前边元素已经是堆的区间的最后一个元素进行上浮操作,调整之后,仍然是堆。 |
72、 | pop_heap() | 区间 + 【二元比较谓词】 对一个构成堆的区间,将首元素与最后一个元素交换,然后调整最后一个元素之前的所有元素为堆。相当于将最后一个元素与首元素交换之后,再对0元素进行下沉操作。真正需要将首元素弹出,需要再调用 .pop_back() 成员函数。 |
73、 | make_heap() | 区间 + 【二元比较谓词】 将一个区间构造成堆。 |
74、 | sort_heap() | 区间 + 【二元比较谓词】 对一个区间进行堆排序。 |
75、 | is_heap() | 区间 + 【二元比较谓词】 判断一个区间是否构成堆。 |
76、 | is_heap_until | 区间 + 【二元比较谓词】 找到某个元素的位置,该元素的左边构成堆,该元素不满足堆。 |
STL中的容器 priority_queue优先队列就是将这些操作封装起来的一个vector<>实现的最大堆,当然在构造函数中可以指定内部容器。(一般非关联容器模板有配置器参数,关联容器模板有比较类型参数,适配的容器有内部默认容器的参数。)
八、求最小值与最大值
函数名 | 参数 | 功能 |
---|---|---|
77、 | min() | 值1 + 值2 + 【二元比较谓词】 返回两个值中的最小值。 |
78、 | max() | 值1 + 值2 + 【二元比较谓词】 返回两个值中的最大值。 |
79、 | minmax() | 值1 + 值2 + 【二元比较谓词】 以pair 的形式返回两个值中的最大值和最小值。 |
80、 | min_element() | 区间 + 【比较谓词】 返回区间中最小值所在的位置。 |
81、 | max_element() | 区间 + 【比较谓词】 返回区间中最大值所在的位置。 |
82、 | minmax_element() | 区间 + 【比较谓词】 以pair的形式返回最大值和最小值所在的位置。 |
九、比较
函数名 | 参数 | 功能 |
---|---|---|
83、 | lexicographical_compare() | 区间1 + 区间2 按字典序比较两个区间的大小,即是对应元素依次比较。 |
10、全排列
函数名 | 参数 | 功能 |
---|---|---|
84、 | next_permutation() | 区间 + 【比较谓词】 按字典序,判断是否还有上一个全排列。 |
85、 | prev_permutation(0 | 区间 + 【比较谓词】 按字典序,判断是否还有上一个全排列。 |
根据字典序找到下一个全排列的方法:从右往左,找到第一个比相邻的右边元素大的元素为标记位置,再从右往左,找到一个个比标记位置元素大的元素,交换该元素和标记位置的元素,然后将标记位置之后的所有元素逆序即可。