C++实现查找中位数的O(N)算法和Kmin算法

C++实现查找中位数的O(N)算法和Kmin算法

中位数

  • 中位数指的是一组数据中间位置的数。
  • 对于一组无序数据而言,可以使用快速排序、堆排序等算法求出其中位数。
  • 但是这些算法的时间复杂度较高。
  • 在此讨论的是时间复杂度为O(N)的算法。

O(N)算法

  • O(N)算法的基本思想:将一组数据分成若干组,然后对于每一组进行处理。
  • 首先随机选择一个数作为参考数,然后将数据分为两组,一组比参考数小,另一组比参考数大。
  • 此时有三种情况:
  • 分组后小于参考数的组中元素个数等于N/2,则中位数为参考数;
  • 小于参考数的组中元素个数小于N/2,在大于参考数的组中递归搜索中位数;
  • 小于参考数的组中元素个数大于N/2,在小于参考数的组中递归搜索中位数。

  • 通过以上三种情况,可以保证每次递归后搜索的数据量都会减半,实现了O(N)的时间复杂度。

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

int nums[100005];

// 搜索中位数
int searchmid(int l,int r,int k){
    if(l+1>=r)return nums[l];
    int i=l+1,j=r-1,x=nums[l];
    while(i<j){
        while(nums[i]<=x && i<j)i++;
        while(nums[j]>x)j--;
        if(i<j)swap(nums[i],nums[j]);
    }
    if(nums[l]<nums[j-1])swap(nums[l],nums[j-1]);
    else{
        j--;
        swap(nums[l],nums[j]);
    }
    if(j-l==k)return nums[j];
    if(j-l>k)return searchmid(l,j,k);
    else return searchmid(j,r,k-j+l);
}

int main(){
    // 读入数据
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>nums[i];
    // 搜索中位数
    int ans=searchmid(0,n,k);
    // 输出结果
    cout<<ans<<endl;
    return 0;
}

Kmin算法

  • Kmin算法的目标是查找一组数据中第K小的数据。
  • 思路为沿用O(N)算法的分组思路,对于每一组确定其最小值$min_l$和最大值$max_r$,找到一组数,使其小于或等于$max_r$,大于或等于$min_l$,则其中必然包含第K小的数。
#include<bits/stdc++.h>
using namespace std;

int nums[100005];

// 寻找第k小的数
int searchkmin(int l,int r,int k){
    if(l+1>=r)return nums[l];
    int m=rand()%(r-l)+l;
    swap(nums[m],nums[l]);
    int i=l+1,j=r-1,x=nums[l];
    while(i<j){
        while(nums[i]<=x && i<j)i++;
        while(nums[j]>x)j--;
        if(i<j)swap(nums[i],nums[j]);
    }
    if(nums[l]<nums[j-1])swap(nums[l],nums[j-1]);
    else{
        j--;
        swap(nums[l],nums[j]);
    }
    if(j-l==k)return nums[j];
    if(j-l>k)return searchkmin(l,j,k);
    else return searchkmin(j,r,k-j+l);
}

int main(){
    // 读入数据
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>nums[i];
    // 寻找第k小的数
    int ans=searchkmin(0,n,k);
    // 输出结果
    cout<<ans<<endl;
    return 0;
}

示例

示例一

输入:

5 3
3 4 2 5 1

输出:

3

说明:

查找第三小的数。

分组后:小于2的数组合为{1},大于2的数组合为{3,4,5}。

小于2的数组合包含0个第三小的数,需要在大于2的数组合中查找第三小的数。

分组后:小于4的数组合包含3个数,大于4的数组合包含1个数。

小于4的数组合中第三小的数位于大于4的数组合中,继续查找第三小的数。

分组后:小于3的数组合中包含两个数,等于3的数组合中包含一个数。

查找结束,找到的第三小的数为3。

示例二

输入:

7 5
-1 2 -2 5 10 -5 4

输出:

2

说明:

查找第五小的数。

分组后:小于$-2$的数组合为$-5$,等于$-2$的数组合为空,大于$-2$的数组合为$-1,2,5,10,4$。

小于$-2$的数组合包含0个第五小的数,需要在大于$-2$的数组合中查找第五小的数。

分组后:小于$4$的数组合包含4个数,大于$4$的数组合包含2个数。

小于$4$的数组合中包含第五小的数,继续查找第五小的数。

分组后:小于$2$的数组合为$-1,-2$,等于$2$的数组合为空,大于$2$的数组合为$5,10$。

小于$2$的数组合包含3个第五小的数,需要在大于$2$的数组合中查找第$5-3=2$小的数。

分组后:小于$5$的数组合包含2个数,等于$5$的数组合包含一个数。

查找结束,找到的第五小的数为2。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++实现查找中位数的O(N)算法和Kmin算法 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • @Async异步线程池以及线程的命名方式

    下面我将为您详细讲解“@Async异步线程池以及线程的命名方式”的攻略。 什么是@Async异步线程池 在Spring中,使用@Async注解来使用异步线程。@Async用于在方法执行时,将方法内的操作放在异步线程中执行,以达到并发执行的效果。在异步方法中,可以使用Future类型来获取异步方法返回的结果。 Spring的@Async注解默认使用的是Simp…

    C 2023年5月23日
    00
  • C++实现简单职工管理系统

    C++实现简单职工管理系统攻略 功能需求 我们需要实现一个简单的职工管理系统,其具有以下功能: 增加职工:可以手动输入职工信息,包括职工编号、职工姓名、职工岗位,职工编号不可重复。 显示所有职工:可以显示所有职工的信息。 删除职工:可以根据职工编号删除职工。 修改职工:可以根据职工编号修改职工信息。 查找职工:可以根据职工编号或者职工姓名查找职工信息。 排序…

    C 2023年5月23日
    00
  • C++强制类型转换(static_cast、dynamic_cast、const_cast、reinterpret_cast)

    下面是关于C++中四种强制类型转换的攻略。 1. static_cast static_cast是安全的类型转换,主要用于基本数据类型之间的转换,还可以在继承类之间进行类型转换。它可以将一个值从一种数值类型转换为另一种数值类型或提升或降低算术类型的类型。在用于指针时,可以将任何类型的指针转换为void指针,也可以将void指针转换为任何类型的指针。但是,它不…

    C 2023年5月23日
    00
  • C 语言基础教程(我的C之旅开始了)[四]

    标题:C语言基础教程——第四章 本文讲解C语言基础教程第四章的内容,主要涵盖了指针和函数相关的知识点。 1.指针 1.1指针的定义和基本操作 指针是一个变量,其值为另一个变量的地址。可以使用“&”符号获取变量的地址,使用“*”符号获取指针指向的变量的值。 int a = 10; int *p = &a; printf("%d\n&q…

    C 2023年5月23日
    00
  • C语言中如何进行面向对象编程?

    在C语言中进行面向对象编程(Object-Oriented Programming)可以采用结构体(Struct)和指针(Pointer)的方式来实现。 首先,我们需要定义一个结构体,包含对象的属性和方法。属性可以使用变量来定义,方法可以使用函数指针来定义。例如: typedef struct { int x; int y; void (*draw)(voi…

    C 2023年4月27日
    00
  • Rust处理错误的实现方法

    当我们在编写 Rust 代码时,不可避免地会遇到错误。Rust 的错误处理机制允许我们有效地处理和跟踪错误,以确保程序稳定的运行。 在 Rust 中,错误通常被表示为实现了 std::error::Error trait 的结构体。这个 trait 定义了两个方法,description() 和 cause(),分别用于返回错误信息和错误原因。我们也可以通过…

    C 2023年5月23日
    00
  • C语言编写获取Linux本地目录及本机信息的小程序实例

    下面是详细讲解“C语言编写获取Linux本地目录及本机信息的小程序实例”的完整攻略: 1. 程序的概要 该程序主要通过C语言来获取Linux本地目录以及本机信息,包括以下功能: 获取当前程序所在目录 获取主机名和IP地址 获取系统空闲内存大小 获取磁盘剩余空间大小 获取系统时间 2. 程序实现步骤 2.1 获取当前程序所在目录 要获取当前程序所在目录,可以使…

    C 2023年5月23日
    00
  • C语言实现飞机大战小游戏

    C语言实现飞机大战小游戏完整攻略 简介 飞机大战是一款经典的小游戏,它的玩法简单却精巧,是C语言初学者不错的练手项目。本文将详细介绍如何用C语言实现飞机大战小游戏。 准备工作 在开始编写游戏代码前,我们需要做一些准备工作: 安装开发环境(比如 Visual Studio Code,CodeBlocks 等等); 了解游戏窗口、控件绘制、键盘事件等基础知识。 …

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部