C++的算法库功能强大,但是很多时候还是习惯手写 for 循环,记录一下常用的几个算法。
排序算法
stable_sort
:稳定排序partial_sort
:选出前几名nth_element
:选出前几名但不要求排序,中位数,第N位数partition
:按照规则对元素分组minmax_element
:同时求出最大最小值。
迭代器的操作函数
prev
,next
:计算前后的某个位置advance
:迭代器自身前进和后退distance
:计算2个迭代器距离之差
查找算法
binary_search(v, x)
,二分查找元素 x 是否存在,只能返回bool,不能找到元素,鸡肋功能。lower_bound(v, x)
:找到第一个 大于或等于 x 的元素的位置的迭代器,可能没找到。用于二分查找找到元素,找到后再判断值。upper_bound(v, x)
:找到第一个 大于 x 的元素的位置的迭代器,可能没找到。equal_range
:可以同时获得[lower_bound, upper_bound] 这个区间。find_if(v, func)
:根据func函数定义的规则,查找某一个元素。find_first_of(v1, v2)
:从v1序列里面查找第一个在v2区间里面出现的元素。
#include <bits/stdc++.h>
#include <source_location>
#include <ranges>
#include <span>
using namespace std;
// 辅助:打印函数的名字
inline void print_func_name()//(const std::ç &location = std::source_location::current())
{
//std::cout << location.function_name() << " :" << endl;
}
inline void print(span<int> nums) {
auto func = [](const int &x) { cout << x << ','; };
std::ranges::for_each(nums, func);
cout << endl;
}
// 找到序列中的最大值和最小值
void min_max(const vector<int> &v) {
print_func_name();
auto [min, max] = std::ranges::minmax_element(v);
cout << *min << ',' << *max << endl;
}
// 类似快排的partition的效果
// 作用:找出前N个最小的数字,并且第n个数字是第N小的
// 注意:N=n+1,n表示0开始的索引,N表示个数
void best_n(vector<int> v, int n = 3) {
print_func_name();
// 找出最小的4个数字,存入 v[0-3],
// 并且,v[n=3]的是第N小
// 但是 v[n] 左右两边的区间不保证排序
std::ranges::nth_element(v, begin(v) + n);
// 打印前 N 个数字,
print({begin(v), next(begin(v), n + 1)});
// 比如 v[3]是区间里面第4小,v[3]和排序之后的v[3]是一样的。
// 比对整个序列进行排序,效率高很多
auto nth = v[n];
std::ranges::sort(v);
assert(nth == v[n]); // 验证v[n]和排序后的效果一样。
}
// 找出中位数
void median(vector<int> v) {
print_func_name();
auto mid_iter = next(begin(v), v.size() / 2);
std::ranges::nth_element(v, mid_iter);
print(v);
cout << "median is " << *mid_iter << endl;
}
// 按照规则对序列分区
void partition(vector<int> v) {
print_func_name();
// 函数返回true的部分,会被移动到前半部分,这里偶数会被放到前半段
std::ranges::partition(v, [](const auto &x) { return x % 2 == 0; });
print(v);
}
// 找出最小的n个数字,然后从小到大的顺序分区
void top_n(vector<int> v, int n = 3) {
print_func_name();
// 数字会直接存到 v[0,n-1]中
std::ranges::partial_sort(v, next(begin(v), n));
print(v);
}
// 对v的前v[0]~v[n-1]区间内的元素排序,并且拷贝
void top_n_copy(vector<int> v, int n = 5) {
print_func_name();
vector<int> w(2); // 前n=5个元素,取最小的2个
// 对 v[0, n) 之间的元素排序,然后拷贝2个到w中,因为w的大小2,所以只会拷贝排序后的前2个。
std::ranges::partial_sort_copy(begin(v), next(begin(v), n), begin(w), end(w));
print(v);
print(w);
}
int main() {
vector<int> v = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
min_max(v);
best_n(v);
median(v);
top_n(v);
top_n_copy(v);
partition(v);
return 0;
}