C++ 之 标准模板库的七大算法
标准模板库的算法
STL中的算法大致可以分为以下七类:
- 不变序列算法
- 变值算法
- 删除算法
- 变序算法
- 排序算法
- 有序区间算法
- 数值算法
特性 :
- 算法就是一个个函数模板,大多数在<algorithm>中定义
- STL中提供能在各种容器中通用的算法,比如查找,排序等
- 算法通过迭代器来操纵容器中的元素。许多算法可以对容器中的一个局部区间进行操作,因此需要两个参数,一个是起始元素的选代器,一个是终止元素的后面一个元素的迭代器。比如,排序和查找
- 有的算法返回一个迭代器。比如find()算法,在容器中查找一个元素,并返回一个指向该元素的迭代器
- 算法可以处理容器,也可以处理普通数组
不变序列算法
- 该类算法不会修改算法所作用的容器或对象
- 适用于顺序容器和关联容器
- 时间复杂度都是O(n)
算法 | 作用 |
---|---|
min | 求两个对象中较小的(可自定义比较器) |
max | 求两个对象中较大的(可自定义比较器) |
min_element | 求区间中的最小值(可自定义比较器) |
max_element | 求区间中的最大值(可自定义比较器) |
for_each | 对区间中的每个元素都做某种操作 |
count | 计算区间中等于某值的元素个数 |
count_if | 计算区间中符合某种条件的元素个数 |
find | 在区间中查找等于某值的元素 |
find_if | 在区间中查找符合某条件的元素 |
find_end | 在区间中查找另一个区间最后一次出现的位置(可自定义比较器) |
find_first_of | 在区间中查找第一个出现在另一个区间中的元素(可自定义比较器) |
adjacent_find | 在区间中寻找第一次出现连续两个相等元素 的位置(可自定义比较器) |
search | 在区间中查找另一个区间第一次出现的位置(可自定义比较器) |
search_n | 在区间中查找第一次出现等于某值的连续n个元素(可自定义比较器) |
equal | 判断两区间是否相等(可自定义比较器) |
mismatch | 逐个比较两个区间的元素,返回第一次发生不相等的两个元素的位置(可自定义比较器) |
lexicographical_compare | 按字典序比较两个区间的大小(可自定义比较器) |
算法示例 : find()
template<class Inlt,class T>
Inlt find(Inlt first,Inlt last,const T& val);
- first和last 这两个参数都是容器的迭代器,它们给出了容器中的查找区间起点和终点[first,last)。区间的起点是位于查找范围之中的,而终点不是。find在[first,last)查找等于val的元素
- 用==运算符判断相等
- 函数返回值是一个迭代器。如果找到,则该选代器指向被找到的元素。
- 如果找不到,则该迭代器等于last
Example:
p=find(v.begin),v.end(),3);
if(!p=v.end())
cout<<*p<<endl;
STL中"大""小"的概念
- 关联容器内部的元素是从小到大排序的
- 有些算法要求其操作的区间是从小到大排序的,称为"有序区间算法"
例:binary_search 二分法/折半查找 - 有些算法会对区间进行从小到大排序,称为"排序算法"
例:sort - 还有一些其他算法会用到"大","小"的概念使用STL时,在缺省的情况下,以下三个说法等价:
- x 比 y 小
- 表达式"x<y"为真
- y 比 x 大
变值算法
- 此类算法会修改源区间或目标区间元素的值
- 值被修改的那个区间,不可以是属于关联容器的
算法 | 作用 |
---|---|
for_each | 对区间中的每个元素都做某种操作 |
copy | 复制一个区间到别处 |
copy_backward | 复制一个区间到别处,但目标区前是从后往前被修改的 |
transform | 将一个区间的元素变形后拷贝到另一个区间 |
swap_ranges | 交换两个区间内容 |
fill | 用某个值填充区间 |
fill_n | 用某个值替换区间中的n个元素 |
generate | 用某个操作的结果填充区间 |
generate_n | 用某个操作的结果替换区间中的n个元素 |
replace | 将区间中的某个值替换为另一个值 |
replace_if | 将区间中符合某种条件的值替换成另一个值 |
删除算法
- 删除一个容器里的某些元素
- 删除--不会使容器里的元素减少
- 将所有应该被删除的元素看做空位子
- 用留下的元素从后往前移,依次去填空位子
- 元素往前移后,它原来的位置也就算是空位子
- 也应由后面的留下的元素来填上
- 最后,没有被填上的空位子,维持其原来的值不变删除算法不应作用于关联容器
- 删除算法不应作用于关联容器
- 算法复杂度都是O(n)的
算法 | 作用 |
---|---|
remove | 删除区间中等于某个值的元素 |
remove_if | 删除区间中满足某种条件的元素 |
remove_copy | 拷贝区间到另一个区间,等于某个值的元素不拷贝 |
remove_copy_if | 拷贝区间到另一个区间,符合某种条件的元素不拷贝 |
unique | 删除区间中连续相等的元素,只留下一个(可自定义比较器) |
unique_copy | 拷贝区间到另一个区间.连续相等的元素,只拷贝第一个到目标区间(可自定义比较器) |
变序算法
- 变序算法改变容器中元素的顺序
- 但是不改变元素的值
- 变序算法不适用于关联容器
- 算法复杂度都是O(n)的
算法 | 作用 |
---|---|
reverse | 颠倒区间的前后次序 |
reverse_Copy | 把一个区间颠倒后的结果拷贝到另一个区间,源区间不变 |
rotate | 将区间进行循环左移 |
rotate_copy | 将区间以首尾相接的形式进行旋转后的结果拷贝到另一个区间,源区间不变 |
next_permutation | 将区间改为下一个排列(可自定义比较器) |
prev_permutation | 将区间改为上一个排列(可自定义比较器) |
random_shuffle | 随机打乱区间内元素的顺序 |
partition | 把区间内满足某个条件的元素移到前面,不满足该条件的移到后面 |
排序算法
- 比前面的变序算法复杂度更高,一般是O(nlog(n))
- 排序算法需要随机访问迭代器的支持不适用于关联容器和list
算法 | 作用 |
---|---|
sort | 将区间从小到大排序(可自定义比较器)将区间从小到大排序 |
stable_sort | 并保持相等元素间的相对次序(可自定义比较器) |
partial_sort | 对区间部分排序,直到最小的n个元素就位(可自定义比较器) |
partial_sort_copy | 将区间前n个元素的排序结果拷贝到别处,源区间不变(可自定义比较器) |
nth_element | 对区间部分排序,使得第n小的元素(n从0开始算)就位,而且比它小的都在它前面,比它大的都在它后面(可自定义比较器) |
排序算法 复杂度分析
sort
- 实际上是快速排序,时间复杂度O(n*log(n))
- 平均性能最优
- 但是最坏的情况下,性能可能非常差,如果要保证"最坏情况下"的性能,那么可以使用stable_sort
stable_sort
- 实际上是归并排序,特点是能保持相等元素之间的先后次序
- 在有足够存储空间的情况下,复杂度为nlog(n),否则复杂度为nlog(n)*log(n)
- stable_sort用法和sort相同.
- 排序算法要求随机存取迭代器的支持,所以ist不能使用
有序区间算法
- 要求所操作的区间是已经从小到大排好序的
- 需要随机访问迭代器的支持
- 有序区间算法不能用于关联容器和list
算法 | 作用 |
---|---|
binary_search | 判断区间中是否包含某个元素 O(log(n)) |
includes | 判断是否一个区间中的每个元素,都在另一个区间中 |
lower_bound | 查找最后一个不小于某值的元素的位置 |
upper_bound | 查找第一个大于某值的元素的位置 |
equal_range | 同时获取lower_bound和upper_bound |
merge | 合并两个有序区间到第三个区间人 |
set_union | 将两个有序区间的并拷贝到第三个区间 |
set_intersection | 将两个有序区间的交拷贝到第三个区间 |
set difference | 将两个有序区间的差拷贝到第三个区间 |
set_symmetric_difference | 将两个有序区间的对称差拷贝到第三个区间 |
inplace_merge | 将两个连续的有序区间原地合并为一个有序区间 |
任世事无常,勿忘初心