C++nth_element接口使用

前言

有这么一类问题,是寻找区间内的第k大或者说第k小(实际上这两个是一个问题),解决算法有排序,权值线段树、主席树、树套树等,但是要么就是复杂度不满意或者不好写。根据快速排序的分治思路,我们还可以在 O ( n ) O(n) O(n)的时间内找到答案,但并不能保证有序,并且STL十分贴心地把这个算法封装到 nth_element 中,本文就是介绍这个接口地使用。

原理

前言中提到,这个接口的期望复杂度是 O ( n ) O(n) O(n) ,我们可以假设每次选取的分段标志为最优大致证明一下:
T ( n ) = T ( n / 2 ) + n = T ( n / 4 ) + n + n / 2 = T ( n / ( 2 i ) ) + n + n / 2... + n / ( 2 ( i − 1 ) ) = n + n / 2 + . . . + 1 = 2 ∗ n − 1 = O ( n ) , 其 中 ( i = l o g ( n ) + 1 ) . T(n) = T(n/2) + n \\ = T(n/4) + n + n/2 \\ = T(n/(2^i)) + n + n/2 ... + n/(2^(i-1)) \\ = n + n/2 + ... + 1 \\ = 2*n - 1 = O(n),其中 (i = log(n) + 1) . T(n)=T(n/2)+n=T(n/4)+n+n/2=T(n/(2i))+n+n/2...+n/(2(i1))=n+n/2+...+1=2n1=O(n)(i=log(n)+1).
至于划分部分和快排一致,区别在于分治部分,具体实现略。

接口

nth_element 默认的比较子和一般的容器都是 less ,这在堆结构中会形成大根堆;在排序接口会形成从小到大排序;在这里则会形成第k小的功能,如果把这个比较子换成greater或者自定义的一个比较子接口则会形成一个第k大。

对于每个参数的含义:

  • 参数1:表示第一个迭代器/指针的位置
  • 参数2:表示要确定的位置,也就是第k小/大的数
  • 参数3:表示最后一个迭代器/指针的位置
  • 参数4:缺省less,可以传入一个比较子

示例

#include <bits/stdc++.h>
using namespace std;

int main() {
    int arr[10] = {2,5,6,9,2,1,3,4,11,12};
    nth_element(arr, arr+2, arr+10); //注意第1小对于下标0,以此类推
    cout << "nth_element(arr, arr+3, arr+10) : ";
    for (int i = 0; i < 10; i++) cout << arr[i] << ' ';
    cout << "\n第3小的数是 : " << arr[2] << endl;
    /**
     * 输出:
     * nth_element(arr, arr+3, arr+10) : 1 2 2 3 4 5 9 6 11 12
     * 第3小的数是 : 2
    */

    int arr2[10] = {2,5,6,9,2,1,3,4,11,12};
    nth_element(arr2, arr2+7, arr2+10); //求第3大转化成求第10-3+1小问题
    cout << "nth_element(arr2, arr2+7, arr2+10) : ";
    for (int i = 0; i < 10; i++) cout << arr2[i] << ' ';
    cout << "\n第3大的数是 : " << arr2[7] << endl;
    /**
     * 输出:
     * nth_element(arr2, arr2+7, arr2+10) : 5 2 4 3 2 1 6 9 11 12
     * 第3大的数是 : 9
    */

    int arr3[10] = {2,5,6,9,2,1,3,4,11,12};
    nth_element(arr3, arr3+2, arr3+10, greater<int>() ); //求第3大转化成求第10-3+1小问题
    cout << "nth_element(arr3, arr3+3, arr3+10, greater<int>()) : ";
    for (int i = 0; i < 10; i++) cout << arr3[i] << ' ';
    cout << "\n第3大的数是 : " << arr3[2] << endl;
    /**
     * 输出:
     * nth_element(arr3, arr3+3, arr3+10, greater<int>()) : 11 12 9 6 5 1 3 4 2 2
     * 第3大的数是 : 9
    */

    int arr4[10] = {2,5,6,9,2,1,3,4,11,12};
    nth_element(arr4, arr4+2, arr4+10, [](int a, int b){ return a > b;}); //求第3大转化成求第10-3+1小问题
    cout << "nth_element(arr4, arr4+2, arr4+10, [](int a, int b){ return a > b;}) : ";
    for (int i = 0; i < 10; i++) cout << arr4[i] << ' ';
    cout << "\n第3大的数是 : " << arr4[2] << endl;
    /**
     * 输出:
     * nth_element(arr4, arr4+2, arr4+10, [](int a, int b){ return a > b;}) : 11 12 9 6 5 1 3 4 2 2
     * 第3大的数是 : 9
    */
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小胡同的诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值