C++ 算法
参考资料
- C++ Standard Template Library in Practice: https://subscription.packtpub.com/video/programming/9781788834995
- Cppreference - Algorithm: https://en.cppreference.com/w/cpp/algorithm
- C++ Standard Library Quick Reference(Peter Van Weert & Marc Gregoire): https://library.kre.dp.ua/Books/2-4 kurs/Програмування %2B мови програмування/С%2B%2B/C%2B%2B Standard Library Quick Reference%40bzd_channel.pdf
说明
- 截止 C++ 17
- 有很多重载的函数,仅写最主要的重载
- 很多算法,并非编译器都有完整的支持
通用概念与基础
-
Function: 函数对象,可以使 lambda 表达式、函数对象,c 风格的函数指针
-
UnaryFunction: 有一个参数的函数
-
BinaryFunction: 有两个参数的函数
-
Predicate: 返回值为 bool 的函数,比如 UnaryPredicate 指的是接受一个参数且返回值为 bool 类型的函数
-
Compare: 一个 BinaryPredicate,接受 2 个参数 T1,T2,返回 T1 是否小于 T2。如果不指定,默认用<比较,需要重载 operator<
-
execution policy: 执行策略
- 备选项可以是
- sequenced_policy: 在调用线程中顺序执行算法
- parallel_policy: 由算法隐式创建线程,并行执行。在每个线程中,算法执行顺序和输入的迭代器顺序一致。比如{1,2,3,4,5}被分到了线程 T1{1,3}和 T2{2,4,5},那么该执行方式保证在 T1 线程中,按照 1->3 的顺序执行;在线程 T2 中,按照 2->4->5 的顺序执行
- parallel_unsequenced_policy: 和前者相同,但不保证单个线程中的执行顺序
- 注意
- 如下算法不一定被编译器支持,甚至很可能不被支持。
- 除非要处理很多元素,否则并行算法效率并不高于顺序执行
- 如果并行算法中涉及竞态条件,需要程序员进行同步
- 备选项可以是
常用非修改型算法
用 for_each 进行遍历
原型
template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
例子
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
vector<int> vec{1,2,3,4,5,6,7,8,9,0};
// transform item of vector to its square
for_each(vec.begin(), vec.end(), [](int& i){
i *= i;
});
// print items
for_each(vec.begin(), vec.end(), [](const int& i){
cout << i << " ";
});
cout << endl;
}
for_each 的返回值是你传入的函数对象,因此 for_each 还可以有更高级的用法。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Sum{
public:
int sum = 0;
void operator() (const int& i){
sum += i;
}
};
int main(){
vector<int> vec{1,2,3,4,5,6,7,8,9,0};
Sum sum;
auto res = for_each(vec.begin(), vec.end(), sum);
cout << res.sum << endl;
}
相似算法
for_each_n
template< class InputIt, class Size, class UnaryFunction >
InputIt for_each_n( InputIt first, Size n, UnaryFunction f );
all_of、any_of、none_of
- all_of: Predicate 是否对所有元素为 true
- any_of: Predicate 是否对至少一个元素为 true
- none_of: Predicate 是否对所有元素都为 false
例子
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
vector<int> vec{1,2,3,4,5,6,7,8,9,0};
cout << any_of(vec.begin(), vec.end(), [](const int& i){ return i >= 4;}) << endl;
cout << all_of(vec.begin(), vec.end(), [](const int& i){ return i >= -1;}) << endl;
cout << none_of(vec.begin(), vec.end(), [](const int& i){ return i <= -1;}) << endl;
}
mismatch 寻找两个序列的不同
原型
template< class InputIt1, class InputIt2 >
constexpr std::pair<InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,
InputIt2 first2 );
参数为:第一个序列的首位迭代器,第二个序列的首迭代器
用户需要保证,第二个迭代器长度不小于第一个
例子
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;
int main(){
auto a = vector{1,2,43,5,6,87,9,0};
decltype(a) b{};
// copy a to b
copy(a.begin(), a.end(), back_inserter(b));
for_each(a.begin(), a.end(), [](const auto& i){cout << i << ' ';}); cout << endl;
for_each(b.begin(), b.end(), [](const auto& i){cout << i << ' ';}); cout << endl;
// change value of b at index 4
b[4] = 9999;
decltype(a.begin()) a_itr;
decltype(b.begin()) b_itr;
tie(a_itr, b_itr) = mismatch(a.begin(), a.end(), b.begin());
// check the index where two itr mismatch
cout << "a and b mismatch at index " << distance(a.begin(), a_itr) << endl;
}
find, find_if, find_if_not 以遍历方式查找元素
原型
// 寻找与T value相同的值的位置
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
// 寻找UnaryPredicate p返回值为True的元素的位置
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last,
UnaryPredicate p );
// 寻找UnaryPredicate p返回值为False的元素的位置
template< class InputIt, class UnaryPredicate >
InputIt find_if_not( InputIt first, InputIt last,
UnaryPredicate q );
例子
int main(){
vector<double> a = vector{1.2,2.4,43.5,5.6,6.8,87.9999,9.1,0.445};
cout << "index of 87.9999 is " << distance(a.begin(), find(a.begin(), a.end(), 87.9999)) << endl;
cout << "index of first value >=5 is " << distance(a.begin(), find_if(a.begin(), a.end(), [](const double i){return i>=5.0;})) << endl;
}
search:在一个序列中查找另一个序列
原型
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
ForwardIt2 s_first, ForwardIt2 s_last,
BinaryPredicate p );
例子
int main(){
string big = "My name is Merry. This is a Message!";
string small = "this";
// search ignore letter case
auto res = search(big.begin(), big.end(), small.begin(), small.end(), [](const char a, const char b){return tolower(a) ==
tolower(b);});
if (res == big.end()) cout << "Cannot find substring" << endl;
else cout << "Find substring at index " << distance(big.begin(), res) << endl;
}
search_n 在序列中寻找连续 n 个相同元素
原型
template< class ForwardIt, class Size, class T >
ForwardIt search_n( ForwardIt first, ForwardIt last, Size count,
const T& value );
例子
int main(){
string big = "10010100100001010110101010110101010101011101010110011000100";
auto res = search_n(big.begin(), big.end(), 4, '0');
if (res == big.end()) cout << "Cannot find!" << endl;
else cout << "Find 0000 at index " << distance(big.begin(), res) << endl;
}
常用修改型算法
"修改型算法"可能是修改原迭代器,也可能是输出一份修改过的值到新的迭代器
copy、copy_if 复制
原型
// 拷贝原迭代器到新的迭代器,程序员应该保证目标迭代器有足够的空间
template< class InputIt, class OutputIt >
OutputIt copy( InputIt first, InputIt last, OutputIt d_first );
// 拷贝UnaryPredicate pred返回true的元素到新的迭代器,程序员应该保证目标迭代器有足够的空间
template< class InputIt, class OutputIt, class UnaryPredicate >
constexpr OutputIt copy_if( InputIt first, InputIt last,
OutputIt d_first,
UnaryPredicate pred );
例子
int main(){
string a = "asdasd12345_21asfsbzxvc";
// copy all string to cout iterator
copy(a.begin(), a.end(), ostreambuf_iterator<char>(cout));
cout << endl;
// copy all letter to cout iterator
copy_if(a.begin(), a.end(), ostreambuf_iterator<char>(cout), [](const char& c){return isalpha(c);});
}
相似算法
copy_backward
template< class BidirIt1, class BidirIt2 >
BidirIt2 copy_backward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last );
从 last 往前拷贝,将元素拷贝到 d_last(倒着拷贝到新迭代器的末尾)
reverse_copy
template< class BidirIt, class OutputIt >
OutputIt reverse_copy( BidirIt first, BidirIt last, OutputIt d_first );
将迭代器倒序拷贝到新的迭代器
改个方式写吧,这样写好像意义不大
举例
sample
int main()
{
std::string in = "hgfedcba", out;
std::sample(in.begin(), in.end(), std::back_inserter(out),
5, std::mt19937{std::random_device{}()});
std::cout << "five random letters out of " << in << " : " << out << '\n';
}
Partition 分区算法
Partition 即将数组分成两部分
算法 | 说明 |
---|---|
partition(first,last, UnaryPredicate) | 将 UnaryPredicate 返回为 true 和 false 的值分成两部分,返回第二个分组的首元素的迭代器。分组后,每个组内元素的相对顺序不保证和原来一样 |
stable_partition | 同上,但是分组完成后,保证每个分组内的元素相对顺序和原来一样 |
sort 排序算法
算法 | 说明 |
---|---|
sort(begin, end, compare) | 按照 compare 所给规则,给元素排序 |
is_sorted(begin, end, compare) | 按照 compare 所给规则,判断元素是否有序 |
is_sorted_until(begin, end) | 到哪个迭代器开始,数组无序 |
partial_sort(begin, end, compare) | 数组排好序之后,前 n 个排好序的元素是什么。这会给数组部分排序 |
stable_sort | 同 sort,但是对于相同元素,保证其排序后的相对顺序和原来一致 |
nth_element(first, nth, last) | 数组排好序之后,第 n 个位置上是什么值。运行过后,第 n 个位置上的值,就是数组完全排好序之后的值。该值左边的值都小于它,右边的值都大于它 |
二分查找
算法 | 说明 |
---|---|
lower_bound | 给出有序迭代器中,不小于某元素的第一个值 |
upper_bound | 给出有序迭代器中,大于某个值的第一个元素 |
其它常用算法
算法 | 说明 |
---|---|
accumulate(first, last, init) | 计算累加和 |
minmax_element | 找到最大和最小元素 |
clamp | 将数组中大于某个值 T 的位置填充为 T,小于某个值 t 的位置填充为 t |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端