1. 不变序列算法
该类算法不会修改算法所作用的容器或对象,适用于顺序容器和关联容器,且时间复杂度都是 O (n) O(n) O(n)。
min
求两个对象中较小的元素(可自定义比较器);max
求两个对象中较大的元素(可自定义比较器);min_element
求区间中的最小值(可自定义比较器);max_element
求区间中的最大值(可自定义比较器);for_each
求区间中的每个元素都做某种操作;count
计算区间中等于某值的元素个数;cound_if
计算区间中符合某种条件的元素个数;find
在区间中查找等于某个值的元素;find_if
在区间中查找符合某种条件的元素;find_end
在区间中查找另一个区间最后一次出现的位置(可自定义比较器);find_first_of
在区间中查找第一个出现在另一个区间中的元素(可自定义比较器);adjacent_find
在区间中寻找第一次出现连续两个相等元素的位置(可自定义比较器);search
在区间中查找另一个区间第一次出现的位置(可自定义比较器);search_n
在区间中查找第一次出现等于某值的连续 n {\rm n} n 个元素(可自定义比较器);equal
判断两区间是否相等(可自定义比较器);mismatch
逐个比较两个区间的元素,返回第一次发生不相等的两个元素的位置(可自定义比较器);lexicographical_compare
按字典序比较两个区间的大小(可自定义比较器)。
示例程序:
#include<iostream>
#include<algorithm>
using namespace std;
class A {
public:
int n;
A(int i) :n(i) {} // 初始化列表
};
// 重载小于符号
bool operator<(const A& a1, const A& a2) {
if (a1.n == 3 && a2.n == 7) {
return true;
}
return false;
}
int main() {
A aa[] = { 3,5,7,2,1 };
// 3,由于小于符号已经重载,3<5为假、3<7为假、3<2为假、3<1为假
cout << min_element(aa, aa + 5)->n << endl;
// 7,由于小于符号已经重载,3>5为假、3>7为真、3<2为假、3<1为假
cout << max_element(aa, aa + 5)->n << endl;
return 0;
}
2. 变值算法
此类算法会修改源区间或目标区间元素的值,且值被修改的那个区间不可以是属于关联容器的。
for_each
对区间的每个元素都做某种操作;copy
复制一个区间到别处;copy_backward
复制一个区间到别处,但目标区间是从后往前修改的;transform
将一个区间的元素变形后拷贝到另一个区间;swap_ranges
交换两个区间的内容;fill
用某个值填充区间;fill_n
用某个值替换区间中的 n {\rm n} n 个元素;generate
用某个操作的结果填充区间;generate_n
用某个操作的结果替换区间中的 n {\rm n} n 个元素;replace
将区间中的某个值替换为另一个值;replace_if
将区间中符合某种条件的值替换成另一个值;replace_copy
将一个区间拷贝到另一个区间,拷贝时某个值要换成新值拷贝过去;replace_copy_if
将一个区间拷贝到另一个区间,拷贝时符号某种条件的值要换成新值拷贝过去。
示例程序:
#include<list>
#include<vector>
#include<numeric>
#include<iterator>
#include<iostream>
#include<algorithm>
using namespace std;
class CLessThen9 {
public:
// 重载圆括号,该类对象为函数对象
bool operator()(int n) {
return n < 9;
}
};
void outputSquare(int value) {
cout << value * value << " ";
}
int calculateCube(int value) {
return value * value * value;
}
int main() {
const int SIZE = 10;
int a1[] = { 1,2,3,4,5,6,7,8,9,10 };
int a2[] = { 100,2,8,1,50,3,8,9,10,2 };
vector<int> v(a1, a1 + SIZE);
// 输出迭代器对象output,使用cout和" "初始化
ostream_iterator<int> output(cout, " ");
// 随机打乱元素
random_shuffle(v.begin(), v.end());
// 9 2 10 3 1 6 8 4 5 7(随机序列)
copy(v.begin(), v.end(), output);
// 拷贝
copy(a2, a2 + SIZE, v.begin());
// 2
cout << count(v.begin(), v.end(), 8);
// 6(小于9的元素个数)
cout << count_if(v.begin(), v.end(), CLessThen9());
// 1
cout << *(min_element(v.begin(), v.end()));
// 100
cout << *(max_element(v.begin(), v.end()));
// 193(所有元素求和)
cout << accumulate(v.begin(), v.end(), 0);
// 10000 4 64 1 2500 9 64 81 100 4
for_each(v.begin(), v.end(), outputSquare);
// 1 8 27 64 125 216 343 512 729 1000
vector<int> cubes(SIZE);
transform(a1, a1 + SIZE, cubes.begin(), calculateCube);
return 0;
}
copy
函数的源代码:
template<class _ll, class_Ol> inline _Ol copy(__ll_F, _ll_L, _Ol_X) {
for (; _F != _L; ++_X, ++_F) {
*_X = *_F;
}
return _X;
}
copy
函数的示例程序:
#include<string>
#include<fstream>
#include<iterator>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int a[4] = { 1,2,3,4 };
My_ostream_iterator<int> oit(cout, "*");
// 1*2*3*4*
copy(a, a + 4, oit);
ofstream oFile("test.txt", ios::out);
My_ostream_iterator<int> oitf(oFile, "*");
// 向test.txt中写入1*2*3*4*
copy(a, a + 4, oitf);
oFile.close();
return 0;
}
现在我们需要自定义My_ostream_iterator
以其可以顺利完成上述功能,这里My_ostream_iterator
类应该重载++
、*
和=
运算符。
template<class T> class My_ostream_iterator :iterator<output_iterator_tag, T> {
private:
string sep; // 分隔符
ostream& os;
public:
My_ostream_iterator(ostream& o, string s):sep(s), os(o){} // 初始化列表
void operator++() {}; // 只需要定义即可,不需要实现具体内容
// 重载"*"运算符
My_ostream_iterator& operator*() {
return *this;
}
// 重载"="运算符
My_ostream_iterator& operator=(const T& val) {
os << val << sep; // 输出内容(屏幕或文件)和分隔符
return *this;
}
};
3. 删除算法
删除算法用于删除一个容器里的某些元素,且删除不会使容器里的元素减少(使用空位置代替),删除算法不应作用于关联容器。
remove
删除区间中等于某个值的元素;remove_if
删除区间中满足某种条件的元素;remove_copy
拷贝区间到另一个区间,等于某个值的元素不拷贝;remove_copy_if
拷贝区间到另一个区间,符合某种条件的元素不拷贝;unique
删除区间中连续相等的元素,只留下一个(可自定义比较器);unique_copy
拷贝区间到另一个区间,连续相等的元素,值拷贝第一个到目标区间(可自定义比较器)。
上述算法的时间复杂度都是 O (n) O(n) O(n)。示例程序:
#include<vector>
#include<iostream>
using namespace std;
int main() {
int a[5] = { 1,2,3,2,5 };
int b[6] = { 1,2,3,2,5,6 };
ostream_iterator<int> oit(cout, ",");
int* p = remove(a, a + 5, 2);
// 1,3,5,2,5
copy(a, a + 5, oit);
// 3
cout << p - a;
vector<int> v(b, b + 6);
remove(v.begin(), v.end(), 2);
// 1,3,5,6,5,6
copy(v.begin(), v.end(), oit);
// 6
cout << v.size();
return 0;
}
4. 变序算法
变序算法用于改变容器中元素的顺序,但是不改变元素的值,并且变序算法不适用于关联容器。
reverse
颠倒区间的前后次序;reverse_copy
把一个区间颠倒后的结果拷贝到另一个区间,源区间不变;rotate
将区间进行循环左移;rotate_copy
将区间以首尾相接的形式进行旋转后的结果拷贝到另一个区间,源区间不变;next_permutation
把区间改为下一个排列(可自定义比较器);prev_permutation
把区间改为上一个排列(可自定义比较器);random_shuffle
随机打乱区间内元素的顺序;partition
把区间内满足某个条件的元素移到前面,不满足该条件的移到后面。
上述算法的时间复杂度都是 O (n) O(n) O(n)。示例程序:
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string str = "231";
char szStr[] = "324";
// 312 321(231后面的排列),且str变为"321"
while (next_permutation(str.begin(), str.end())) {
cout << str << " ";
}
// 342 423 432(324后面的排列)
while (next_permutation(szStr, szStr + 3)) {
cout << szStr << endl;
}
// str变为"123"
sort(str.begin(), str.end());
// 132 213 231 312 321(123后面的排列)
while (next_permutation(str.begin(), str.end())) {
cout << str << endl;
}
return 0;
}
5. 排序算法
排序算法需要随机访问迭代器的支持,不适用关联容器和列表。
sort
将区间从小到大排序(可自定义比较器);stable_sort
将区间从小到大排序,并保持元素的相对位置不变(可自定义比较器);partial_sort
对区间部分排序,直到最小的 n {\rm n} n 个元素就位(可自定义比较器);partial_sort_copy
将区间前 n {\rm n} n 个元素的排序结果拷贝到别处,源区间不变(可自定义比较器);nth_element
对区间部分排序,使得第 n {\rm n} n 小的元素就位,而且比它小的元素在前面,比它大的元素在后面(可自定义比较器);make_heap
使区间称为一个堆(可自定义比较器);push_heap
将元素加入一个堆(可自定义比较器);pop_heap
从堆区间删除堆顶元素(可自定义比较器);sort_heap
将一个堆区间进行排序,排序结束后,该区间就是普通的有序区间,不再是堆了(可自定义比较器)。
上述算法的时间复杂度都是 O ( n log (n) ) O(n\log(n)) O(nlog(n))。示例程序:
#include<iostream>
#include<algorithm>
using namespace std;
class MyLess {
public:
// 重载圆括号,个位较大者较大
bool operator()(int n1, int n2) {
return (n1 % 10) < (n2 % 10);
}
};
int main() {
int a[] = { 14,2,9,111,78 };
sort(a, a + 5, MyLess());
// 111 2 14 78 9
for (int i = 0; i < 5; ++i) {
cout << a[i] << " ";
}
sort(a, a + 5, greater<int>());
// 111 78 14 9 2
for (int i = 0; i < 5; ++i) {
cout << a[i] << " ";
}
return 0;
}
6. 有序区间算法
有序区间算法要求所操作的区间已经是从小到大排好序的,需要随机访问迭代器的支持,不适用关联容器和列表。
binary_search
判断区间中是否包含某个元素;includes
判断是否一个区间中的每个元素,都在另一个区间中;lower_bound
查找最后一个不小于某值的元素的位置;upper_bound
查找第一个大于某值的元素的位置;equal_range
同时获取lower_bound
和upper_bound
的值;merge
合并两个有序区间到第三个区间;set_union
将两个有序区间的并拷贝到第三个区间;set_intersection
将两个有序区间的交拷贝到第三个区间;set_difference
将两个有序区间的差拷贝到第三个区间;set_symmetric_difference
将两个有序区间的对称差拷贝到第三个区间;inplace_merge
将两个连续的有序区间原地合并并作为一个有序区间。
示例程序:
#include<list>
#include<bitset>
#include<vector>
#include<numeric>
#include<iostream>
#include<algorithm>
using namespace std;
bool Greater10(int n) {
return n > 10;
}
int main() {
const int SIZE = 10;
int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
vector<int> v(a1, a1 + SIZE);
ostream_iterator<int> output(cout, " ");
vector<int>::iterator location;
location = find(v.begin(), v.end(), 10);
// 找到,输出8
if (location != v.end()) {
cout << location - v.begin();
}
location = find_if(v.begin(), v.end(), Greater10);
// 找到,输出3(第一个满足Greater10的元素位置)
if (location != v.end()) {
cout << location - v.begin();
}
sort(v.begin(), v.end());
// 找到9,输出Founded
if (binary_search(v.begin(), v.end(), 9)) {
cout << "Founded";
}
return 0;
}
7. 数值算法
数值算法主要是对容器类中的元素进行相应的数值操作。
accumulate
计算容器内各元素的总和;iota
用于填充容器指定范围内的元素;adjacent_difference
计算容器内相邻元素的差值;inner_product
计算容器内元素的内积;gcd
用来求两个正整数的最大公约数(辗转相除法);lcm
用来求两个正正整数的最小公倍数。