变序算法
- 变序算法改变容器中元素的顺序
- 但是不改变元素的值
- 变序算法不适用于关联容器
- 算法复杂度大部分都是 O ( n ) O(n) O(n)的
算法 | 功能 |
---|---|
reverse | 颠倒区间的前后次序 |
reverse_copy | 把一个区间颠倒后的结果拷贝到另一个区间, 源区间不变 |
rotate | 将区间进行循环左移 |
rotate_copy | 将区间以首尾相接的形式进行旋转后的结果 拷贝到另一个区间,源区间不变 |
next_permutation | 将区间改为下一个排列(可自定义比较器) |
prev_permutation | 将区间改为上一个排列(可自定义比较器) |
random_shuffle | 随机打乱区间内元素的顺序 |
partition | 把区间内满足某个条件的元素移到前面,不满足该 条件的移到后面 |
stable_partition
- 把区间内满足某个条件的元素移到前面
- 不满足该条件的移到后面
- 而对这两部分元素, 分别保持它们原来的先后次序不变
random_shuffle
原型
template<class RanIt>
void random_shuffle(RanIt first, RanIt last);
- 随机打乱[first,last) 中的元素, 适用于能随机访问的容器
reverse
原型
template<class BidIt>
void reverse(BidIt first, BidIt last);
- 颠倒区间[first,last)顺序
next_permutation
原型
template<class InIt>
bool next_permutaion (Init first,Init last);
- 求下一个排列
示例
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
string str = "231";
char szStr[] = "324";
while (next_permutation(str.begin(), str.end()))//参数为起点,终点
{
cout << str << endl;//312,321
}
cout << "****" << endl;
while (next_permutation(szStr, szStr + 3))
{
cout << szStr << endl;
}
sort(str.begin(), str.end());
cout << "****" << endl;
while (next_permutation(str.begin(), str.end()))
{
cout << str << endl;
}
return 0;
}
next_permutation
不单单可以用在数字上,也可以用在自定义的数据类型上
。
using namespace std;
int main() {
int a[] = {8,7,10};
list<int>ls(a, a + 3);
while (next_permutation(ls.begin(), ls.end())) {
list<int>::iterator i;
for (i + ls.begin; i != ls.end(); i++) {
cout << *i << " ";
cout << endl;
}
}
}
排序算法
- 比前面的变序算法复杂度更高, 一般是 O ( n log ( n ) ) O(n\log(n)) O(nlog(n))
- 排序算法需要随机访问迭代器的支持
- 不适用于关联容器和
list
(list
是双向迭代器,要使用list::sort
)
算法 | 功能 |
---|---|
sort | 将区间从小到大排序(可自定义比较器) |
stable_sort | 将区间从小到大排序, 并保持相等元素间的相对次序(可自定义比较器) |
partial_sort | 对区间部分排序, 直到最小的n个元素就位(可自定义比较器) |
partial_sort_copy | 将区间前n个元素的排序结果拷贝到别处, 源区间不变(可自定义比较器) |
nth_element | 对区间部分排序, 使得第n小的元素(n从0开始算)就位, 而且比 它小的都在它前面, 比它大的都在它后面(可自定义比较器) |
make_heap | 使区间成为一个“堆”(可自定义比较器) |
push_heap | 将元素加入一个是“堆”区间(可自定义比较器) |
pop_heap | 从“堆”区间删除堆顶元素(可自定义比较器) |
sort_heap | 将一个“堆”区间进行排序,排序结束后,该区间就是普 通的有序区间,不再是 “堆”了(可自定义比较器) |
sort
原型1
template<class RanIt>
void sort(RanIt first, RanIt last);
- 按升序排序
- 没有自定义比较器时,判断x是否应比y靠前, 就看 x < y 是否为true
原型2
template<class RanIt, class Pred>
void sort(RanIt first, RanIt last, Pred pr);
- 按升序排序
- 判断x是否应比y靠前, 就看
pr(x,y)
是否为true,此时pr
为函数对象或函数指针
sort 实际上是快速排序, 时间复杂度 $O(n\log(n)) $
- 平均性能最优
- 但是最坏的情况下, 性能可能非常差 O ( n 2 ) O(n^2) O(n2)
如果要保证 “最坏情况下” 的性能, 那么可以使用 stable_sort
stable_sort
实际上是归并排序, 特点是能保持相等元素之间的先后次序- 在有足够存储空间的情况下, 复杂度为 n log ( n ) n\log(n) nlog(n), 否则复杂度为 n log ( n ) log ( n ) n\log(n)\log(n) nlog(n)log(n)
stable_sort
用法和sort
相
同。
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;
class MyLess {
public:
bool operator() (int n1, int n2) {
return (n1 % 10) < (n2 % 10);
}
};
class MyGreater {
public:
bool operator() (int n1, int n2) {
return n1 > n2;
}
};
int main() {
int a[] = { 14,2,9,111,78 };
sort(a, a + 5, MyLess());
int i;
for (i = 0; i < 5; i++) {
cout << a[i] << " ";
}
cout << endl;
sort(a, a + 5, greater<int>());
for (i = 0; i < 5; i++)
cout << a[i] << " ";
cout<<endl;
sort(a,a+5,MyGreater());
for (i = 0; i < 5; i++)
cout << a[i] << " ";
}
输出结果如下:
111 2 14 78 9 //按个位数比大小
111 78 14 9 2 //系统自带greater
111 78 14 9 2 //自己定义greater
有序区间算法
- 要求所操作的区间是已经从小到大排好序的
- 需要随机访问迭代器的支持
- 有序区间算法不能用于关联容器和list
算法 | 功能 |
---|---|
binary_search | 判断区间中是否包含某个元素 此处的相等是 == ,体现在程序里是x<y,y<x同时不成立 |
includes | 判断是否一个区间中的每个元素,都在另一个区间中 |
lower_bound | 查找最后一个不小于某值的元素的位置 |
upper_bound | 查找第一个大于某值的元素的位置 |
equal_range | 同时获取lower_bound和upper_bound |
merge | 合并两个有序区间到第三个区间 |
set_union | 将两个有序区间的并拷贝到第三个区间,允许有重复元素 |
set_intersection | 将两个有序区间的交拷贝到第三个区间 |
set_difference | 将两个有序区间的差拷贝到第三个区间 |
set_symmetric_difference | 将两个有序区间的对称差拷贝到第三个区间KaTeX parse error: Expected 'EOF', got '\or' at position 2: A\̲o̲r̲ ̲B-A\and B |
inplace_merge | 将两个连续的有序区间原地合并为一个有序区间 |
binary_search
- 折半查找
- 要求容器已经有序且支持随机访问迭代器, 返回是否找到
bool
原型1
template<class FwdIt, class T>
bool binary_search(FwdIt first, FwdIt last, const T& val);
- 比较两个元素x, y 大小时, 看 x < y
原型2
template<class FwdIt, class T, class Pred>
bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr);
- 比较两个元素x, y 大小时, 若
pr(x,y)
为true, 则 认为x小于y
lower_bound
template<class FwdIt, class T>
FwdIt lower_bound(FwdIt first, FwdIt last, const T& val);
- 要求[first,last)是有序的
- 查找[first,last)中的, 最大的位置 FwdIt, 使得[first,FwdIt) 中所有的元素都比 val 小
equal_range
template<class FwdIt, class T>
pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last, const T& val);
- 要求[first,last)是有序的
- 返回值是一个pair, 假设为 p, 则:
- [first,p.first) 中的元素都比 val 小
- [p.second,last)中的所有元素都比 val 大
- p.first 就是lower_bound的结果
- p.last 就是 upper_bound的结果
merge
- 把[first1,last1), [ first2,last2) 两个升序序列合并, 形成第 3 个升序序列, 第3个升序序列以 x 开头
原型1
template<class InIt1, class InIt2, class OutIt>
OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x);
- 用 < 作比
较器
原型2
template<class InIt1, class InIt2, class OutIt, class Pred>
OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);
- 用 pr 作比较器
includes
template<class InIt1, class InIt2>
bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2);
template<class InIt1, class InIt2, class Pred>
bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, Pred pr);
判断[First2, last2)中的每个元素,是否都在[First1,last1)中:
- 第一个用
<
作为比较器,x<y,y<x都不成立 - 第二个用pr, pr(x,y)==true说明x,y相等
set_difference
- 求出[first1,last1)中, 不在[first2,last2)中的元素, 放到从 x 开始的地方
- 如果 [first1,last1) 里有多个相等元素不在[first2,last2)中, 则这多个元素也都会被放入x代表的目标区间里
template<class InIt1, class InIt2, class OutIt>
OutIt set_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x);
template<class InIt1, class InIt2, class OutIt, class Pred>
OutIt set_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt x, Pred pr);
set_intersection
- 求出[first1,last1)和[first2,last2)中共有的元素, 放到从x开始的 地方
- 若某个元素e 在[first1,last1)里出现 n1次, 在[first2,last2)里出 现n2次, 则该元素在目标区间里出现min(n1,n2)次
set_union
- 求两个区间的并, 放到以 x开始的位置
- 若某个元素e 在[first1,last1)里出现 n1次, 在[first2,last2)里 出现n2次, 则该元素在目标区间里出现max(n1,n2)次