C++20 ranges版本的排序+查找算法

C++的算法库功能强大,但是很多时候还是习惯手写 for 循环,记录一下常用的几个算法。

排序算法

  • stable_sort:稳定排序
  • partial_sort:选出前几名
  • nth_element:选出前几名但不要求排序,中位数,第N位数
  • partition:按照规则对元素分组
  • minmax_element:同时求出最大最小值。

迭代器的操作函数

  • prevnext:计算前后的某个位置
  • 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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值