STL算法
STL算法由头文件<algorithm>
, <numeric>
和 <functional>
组成的。
其中**<algorithm>
**:这是STL中最大的头文件,包括了各种常用算法,如:比较,交换,查找,遍历,复制,修改,排序等相关操作。
<numeric>
这个头文件相对较小,他主要包括了序列上进行数学运算法的模板函数。如:累积,内积,部分和,相邻差异等。
<functional>
这个头文件定义了一些模板类,用于声明函数对象(也称为仿函数)。这些函数对象经常用于STL算法中,特别是那些需要自定义比较或操作的算法。如:比较,逻辑操作等。
常用遍历算法
for_each
for_each它允许将给定函数或可调用对象应用于范围中的每个函数。也就是说它会遍历集合中每一个元素,然后执行你需要的操作。
for_each
的函数模板
template<class InputIt, class UnaryFunction>
unaryFuction for_each(InputIt first, InputIt last, UnaryFunction f);
InputIt
: 元素范围开头和结尾的输入迭代器类型。
UnaryFunction
: 一元函数的类型。
返回值是函数将可调用对象f
应用到范围中的每个元素后返回。
我将介绍一下for_each的基本实现
template<typename Iterator, typename Func>
void My_for_each(Iterator begin, Iterator end, Func f){
while(begin != end){
f(*begin);
++begin;
}
}
下面是用My_for_each调用函数的操作。
#include<iostream>
#include<vector>
using namespace std;
template<typename Iterator, typename Func>
void My_for_each(Iterator begin, Iterator end, Func f){
while(begin != end){
f(*begin);
++begin;
}
}
class PrintDouble{
public:
void operator()(int i) const{
cout<< i * 2<<" ";
}
};
int main(){
vector<int> number = {1,2,3,4,5};
My_for_each(number.begin(), number.end(),[](int n){
cout<< n <<" ";
});
cout<<endl;
My_for_each(number.begin(), number.end(), PrintDouble());
return 0;
}
Note:
One interesting thing to note about
for_each
is that the function or callable can have side effects. Meaning , they can change the state of objects outside of their own scope.Beside,the returned function object (
f
) can be used after thefor_each
call, especially if it maintains a state. For example, if you want to count occurrences of a certain condition, the callable object can keep a counter which will be available after the execution offor_each
.
transform
transform
与for_each
的算法操作类似,它是对给定范围内的每个元素应用指定操作,并且将结果储存在另一个范围中。
transform
的函数模板如下,
template<class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform(InputIterator first1, InputIterator last1, OutputIterator result, UnaryOperation op){
while(first1 != last1){
*result = op(*first1);
++result;
++first1;
}
return result;
}
其中result
是一个迭代器,指向存储转换后的值的目标范围的开头。
下面是一个简单示例:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> input = {1, 2, 3, 4, 5};
vector<int> output(input.size());
// Use std::transform to double each element in input and store in output
transform(input.begin(), input.end(), output.begin(), [](int x) {
return x * 2;
});
// Print the transformed values in output
for (int val : output) {
cout << val << " ";
}
return 0;
}
常用查找算法
find
在给定的范围内查找指定的元素。如果找到,返回指定第一个匹配元素的迭代器;否则返回范围的末尾。
vector<int> v = {1, 2, 3, 4, 5};
auto it = find(v.begin(), v.end(), 3);
if (it != v.end()) {
cout << "Found the value: " << *it << endl;
} else {
cout << "Value not found." << endl;
}
find_if
在给定的范围内查找满足特定条件的第一个元素。
vector<int> v = {1, 2, 3, 4, 5};
auto it = find_if(v.begin(), v.end(), [](int x){ return x > 3; });
if (it != v.end()) {
cout << "First value greater than 3: " << *it << endl;
} else {
cout << "No values found greater than 3." << endl;
}
adjacent_find
在给定的范围内查找第一对相邻的匹配元素。
vector<int> v = {1, 2, 3, 3, 4};
auto it = adjacent_find(v.begin(), v.end());
if (it != v.end()) {
cout << "Found adjacent value: " << *it << endl;
} else {
cout << "No adjacent matching values found." << endl;
}
binary_search
在一个排序的范围内使用二分查找法检查一个元素是否存在。返回一个bool值,表示元素是否存在。
vector<int> v = {1, 2, 3, 4, 5};
if (binary_search(v.begin(), v.end(), 3)) {
cout << "Value 3 exists." << endl;
} else {
cout << "Value 3 does not exist." << endl;
}
count
在给定的范围内统计指定元素的出现次数
vector<int> v = {1, 2, 3, 4, 5, 3};
int num = count(v.begin(), v.end(), 3);
cout << "Number 3 appears " << num << " times." << endl;
count_if
在给定的范围内统计满足特定条件的元素的数量
int num = count_if(v.begin(), v.end(), [](int x){ return x > 3; });
cout << "Number of values greater than 3: " << num << endl;
常用排序算法
sort
对给定范围内的元素进行排序。
默认按升序排序。如果想要降序或者其他类型排序,可以提供自定义的比较函数
vector<int> v = {4,5,8,55,7,2,1,9};
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), [](int x){cout << x << " ";});
cout << endl;
// 降序
sort(v.begin(), v.end(), [](int x, int y){return x > y;});
for_each(v.begin(), v.end(), [](int x){cout << x << " ";});
random_shuffle
对给定范围的元素进行随机重新排列。(在c++17中这个函数已经被shuffle取代。)
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;
vector<int> v = {1, 2, 3, 4, 5};
srand(time(nullptr)); // 设置随机数种子
random_shuffle(v.begin(), v.end());
for (int i : v) {
cout << i << " ";
} // 输出可能为: 3 5 1 4 2
merge
合并两个已排序的范围,并存储到另一个容器内。
#include <algorithm>
#include <vector>
using namespace std;
vector<int> a = {1, 3, 5};
vector<int> b = {2, 4, 6};
vector<int> result(a.size() + b.size());
merge(a.begin(), a.end(), b.begin(), b.end(), result.begin());
for (int i : result) {
cout << i << " ";
} // 输出: 1 2 3 4 5 6
reverse
反转给定范围的元素。
vector<int> v = {1, 2, 3, 4, 5};
reverse(v.begin(), v.end());
for (int i : v) {
cout << i << " ";
} // 输出: 5 4 3 2 1
常用拷贝和替换函数
copy
将一个容器内的指定范围的元素拷贝到另一个容器中。
vector<int> source = {1, 2, 3, 4, 5};
vector<int> destination(source.size());
copy(source.begin(), source.end(), destination.begin());
for (int i : destination) {
cout << i << " ";
} // 输出: 1 2 3 4 5
replace
将容器内指定范围的旧元素替换为新元素。
vector<int> v = {1, 2, 3, 4, 3};
replace(v.begin(), v.end(), 3, 99);
for (int i : v) {
cout << i << " ";
} // 输出: 1 2 99 4 99
replace_if
将容器内指定范围满足条件的元素替换为新元素。
vector<int> v = {1, 2, 3, 4, 5};
replace_if(v.begin(), v.end(), [](int n) { return n > 3; }, 99);
for (int i : v) {
cout << i << " ";
} // 输出: 1 2 3 99 99
swap
交换两个容器(或两个元素)的内容。
vector<int> a = {1, 2, 3};
vector<int> b = {4, 5, 6};
swap(a, b);
for (int i : a) {
cout << i << " ";
} // 输出: 4 5 6
for (int i : b) {
cout << i << " ";
} // 输出: 1 2 3
常用算法生成算法
accumulate
计算给定范围内元素的累计总和
函数原型:accumulate(iterator beg, iterator end, value);
其中value是起始值
#include <numeric>
#include <vector>
using namespace std;
vector<int> v = {1, 2, 3, 4, 5};
int sum = accumulate(v.begin(), v.end(), 0);
cout << sum; // 输出: 15
备注: accumulate
也可以用来进行其他二元操作,例如累乘,但这需要提供一个自定义的二元函数。
fill
为容器内指定范围的所有元素设置一个新的值。
#include <algorithm>
#include <vector>
using namespace std;
vector<int> v(5); // 创建一个大小为5的vector,所有元素默认初始化为0
fill(v.begin(), v.end(), 42);
for (int i : v) {
cout << i << " ";
} // 输出: 42 42 42 42 42
备注: 虽然fill
被定义在<algorithm>
中,但是与accumulate
一样,它也可以被看作是一个算术生成算法。
常用集合算法
set_intersection
求两个已排序的范围的交集。
函数原形:
template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
OutputIterator result);
result
是目标容器的开始迭代器
#include <algorithm>
#include <vector>
using namespace std;
vector<int> a = {1, 2, 3, 4, 5};
vector<int> b = {4, 5, 6, 7, 8};
vector<int> intersection;
set_intersection(a.begin(), a.end(), b.begin(), b.end(), back_inserter(intersection));
for (int i : intersection) {
cout << i << " ";
} // 输出: 4 5
注意: 输入范围必须是已排序的。输出不会自动删除重复元素。
set_union
求两个已排序的范围的并集。
vector<int> a = {1, 2, 3, 4};
vector<int> b = {3, 4, 5, 6};
vector<int> union_result;
set_union(a.begin(), a.end(), b.begin(), b.end(), back_inserter(union_result));
for (int i : union_result) {
cout << i << " ";
} // 输出: 1 2 3 4 5 6
set_difference
求两个已排序的范围的差集(即第一个范围中存在但第二个范围中不存在的元素)。
vector<int> a = {1, 2, 3, 4, 5};
vector<int> b = {4, 5, 6, 7, 8};
vector<int> difference;
set_difference(a.begin(), a.end(), b.begin(), b.end(), back_inserter(difference));
for (int i : difference) {
cout << i << " ";
} // 输出: 1 2 3