数组中求第K大数的实现方法

问题:有一个大小为n的数组A[0,1,2,…,n-1],求其中第k大的数。
该问题是一个经典的问题,在《算法导论》中被作为单独的一节提出,而且其解决方法很好的利用了分治的思想,将时间复杂度控制在了O(n),这多少出乎我们的意料,此处暂且不表。
该问题还可以变形为:有一个大小为 n的数组A[0,1,2,…,n-1],求其中前k大的数。
一字之差,原问题是“第k大”,变形的问题是“前k大”,但是平均时间复杂度却都可以控制在O(n),这不由得让人暗暗称奇。

我们先分析原问题:有一个大小为 n的数组A[0,1,2,…,n-1],求其中第k大的数。
我们先取特例,令k=1,那么就是取最大的数,只要扫描一遍数组就可以确定该值,如果k=2,则扫描两边数组就可以确定第二大的数,依此类推下去,时间复杂度是O(k*n),如果k跟n是一个数量级,那么时间复杂度就是O(n*n)了,显然不是最优的解法。

考虑分治法,难点在于如何将该问题分解为两个子问题。
快速排序最基础的一步:
随机取某一个数x,将其与数组末尾元素交换,然后将比其小的数交换至前,比其大的数交换至后。
这一步使某一数组的快速排序问题分解成两个子数组的排序问题,现在我们就依此来解决取第k大的数这个问题。
设数组下表从0开始,至n-1结束。
1、 随机取某个数,将其与数组末尾元素交换。
a)        idx=rand(0,n-1);生成[0,n-1]间的随机数。
b)        Swap(array[idx], array[n-1]);
2、 用末尾元素x,将比x小的数交换至前,比x大的数交换至后,并返回此时x在数组中的位置mid。
3、 如果mid==n-k,那么返回该值,这就是第k大的数。
如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数。
如果mid<n-k,那么第k大的数在右半数组,而且仍然是第k的数。


复制代码 代码如下:

#include "iostream"
using namespace std;
int random_partion(int *p, int n)
{
     int idx=rand()%n;
     swap(p[idx], p[n-1]);
     int i=-1;    //i表示最后一个小于p[n-1]的元素的位置
     int j=0;     //j用来扫描数组
     for(j=0; j<n; j++)
     {
            //将小于p[n-1]的数交换到前半部分
            if(p[j]<p[n-1])
            {
    swap(p[++i], p[j]);
            }
     }
     swap(p[++i], p[n-1]);
     return i;
}
int getMaxK(int *p, int n, int k)
{
 int mid;
     if(k<=0)
            return -1;
     if(n<k)
            return -1;
  mid=random_partion(p, n);   //对原数组进行一次划分
     if(mid == n-k)      //如果mid==n-k,那么返回该值,这就是第k大的数
   return p[mid];
     else if(mid<n-k)
   return getMaxK(p+mid+1, n-mid-1, k);  //如果mid<n-k,那么第k大的数在右半数组,而且仍然是第k大数
     else
   return getMaxK(p, mid, k-(n-mid));   //如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数
}
int main(void)
{
 int num,a[] = {12012, 3, 945, 965, 66, 232, 65, 7, 8, 898, 56, 878, 170, 13, 5};
 num=getMaxK(a, 15, 4);
 printf("%d\n",num);
 system("pause");
 return 0;
}

时间: 2013-05-22

深入线性时间复杂度求数组中第K大数的方法详解

求数组中第K大的数可以基于快排序思想,步骤如下:1.随机选择一个支点2.将比支点大的数,放到数组左边:将比支点小的数放到数组右边:将支点放到中间(属于左部分)3.设左部分的长度为L,当K < L时,递归地在左部分找第K大的数当K > L时,递归地在有部分中找第(K - L)大的数当K = L时,返回左右两部分的分割点(即原来的支点),就是要求的第K大的数以上思想的代码实现如下: 复制代码 代码如下: /**线性时间复杂度求数组中第K大数** author :liuzhiwei ** data 

深入第K大数问题以及算法概要的详解

解法1: 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*logn + k). 解法2: 利用选择排序或交互排序,K次选择后即可得到第k大的数.总的时间复杂度为O(n*k) 解法3: 利用快速排序的思想,从数组S中随机找出一个元素X,把数组分为两部分Sa和Sb.Sa中的元素大于等于X,Sb中元素小于X.这时有两种情况:1. Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数:2. Sa中元素的个数大于等于k,则返回Sa中的第k大数.时间复杂度近

C#递归算法寻找数组中第K大的数

1.概述 国人向来喜欢论资排辈的,每个人都想当老大,实在当不成,当个老二,老三,老K也不错,您一定看过这样的争论: 两个人吵架,一个人非常强势,另外一个忍受不住了便说:"你算老几呀?",下面就通过这篇文章就是要解决找出老几的问题! 2.应用场景 在向量V[first,last)中查找出第K大元素的值 3.分析 如果利用排序算法将向量V排好序,那么第K大元素就是索引为v.length-k的元素了,这样能解决问题,但效率不高,因为这相当于为了歼灭敌人一个小队而动用了我们全军的力量,得不偿失

如何寻找数组中的第二大数

方法一: 复制代码 代码如下: #include "stdio.h"#include "stdlib.h"//初始化最大值为a[0],次大值为a[1],遍历一次,每次比较并更新最大值和次大值,最后就可以得到次大值.int findsecondmaxvalue(int *a,int size){    int i,max,s_max;    max=a[0];  //最大值 s_max=a[1];  //次大值    for(i=0;i<size;i++)   

Python实现找出数组中第2大数字的方法示例

本文实例讲述了Python实现找出数组中第2大数字的方法.分享给大家供大家参考,具体如下: 题目比较简单直接看实现即可,具体的注释在代码中都有: #!usr/bin/env python #encoding:utf-8 ''''' __Author__:沂水寒城 功能:找出数组中第2大的数字 ''' def find_Second_large_num(num_list): ''''' 找出数组中第2大的数字 ''' #直接排序,输出倒数第二个数即可 tmp_list=sorted(num_lis

JavaScript实现列出数组中最长的连续数

原始题目: 给定一个无序的整数序列, 找最长的连续数字序列. 例如: 给定[100, 4, 200, 1, 3, 2], 最长的连续数字序列是[1, 2, 3, 4]. 小菜给出的解法: 复制代码 代码如下: function maxSequence(array,step){   var _array = array.slice(),  //clone array       _step = 1,       _arrayTemp = [],       i = 0;   var parseLo

C++算法之在无序数组中选择第k小个数的实现方法

本文实例讲述了C++算法之在无序数组中选择第k小个数的实现方法.分享给大家供大家参考,具体如下: 从一个无序的整型数组中选出第k小的数,如k=1为最小数,k=n为最大数.这里数组可以是有重复的值! 下面是自己写的一个函数,记在此处来记忆我留下的痕迹! //选择无序数组中第k小的数 #include <iostream> using namespace std ; bool failed = false ; //这里只考虑数组是int型的 int findnumber(int *array,in

Python实现返回数组中第i小元素的方法示例

本文实例讲述了Python实现返回数组中第i小元素的方法.分享给大家供大家参考,具体如下: #! /usr/bin/env python #coding=utf-8 #期望为线性时间的选择算法 import random class RandomSelect(object): def Partition(self,a, p, r): x=a[r] i=p-1 for j in range(p, r): '''如果a[j]>x,则只需将j的值加1即可使循环不变量继续保持; 如果a[j]<=x,则

Python实现查找数组中任意第k大的数字算法示例

本文实例讲述了Python实现查找数组中任意第k大的数字算法.分享给大家供大家参考,具体如下: 模仿partion方法,当high=low小于k的时候,在后半部分搜索,当high=low大于k的时候,在前半部分搜索.与快排不同的是,每次都减少了一半的排序. def partitionOfK(numbers, start, end, k): if k < 0 or numbers == [] or start < 0 or end >= len(numbers) or k > end

Go语言算法之寻找数组第二大元素的方法

本文实例讲述了Go语言算法之寻找数组第二大元素的方法.分享给大家供大家参考.具体如下: 该算法的原理是,在遍历数组的时,始终记录当前最大的元素和第二大的元素.示例代码如下: 复制代码 代码如下: package demo01    import (      "fmt"  )    func NumberTestBase() {      fmt.Println("This is NumberTestBase")        nums := []int{12, 2