java查找第k大的数字_查找数组中第k大的数

问题:  查找出一给定数组中第k大的数。例如[3,2,7,1,8,9,6,5,4],第1大的数是9,第2大的数是8……

思考:1. 直接从大到小排序,排好序后,第k大的数就是arr[k-1]。

2. 只需找到第k大的数,不必把所有的数排好序。我们借助

算法的时间复杂度为:O(N)--详情参考算法导论。

#include

using namespace std;

int Partition(int a[], int i, int j)

{

int tmp = a[j];

int index =i;

if (i < j)

{

for (int k=i;k

if(a[k] >= tmp){

swap(a[index++],a[k]);

}

}

swap(a[index],a[j]);

return index;

}

}

//参考 https://www.cnblogs.com/wsw-seu/p/14092811.html。k-(m-i+1)这个容易出错

int Search(int a[], int i, int j, int k)

{

int m = Partition(a, i, j);

if (k==m-i+1) return a[m];

else if (k

{

return Search(a, i, m-1,k );

}

//后半段

else

{

//核心后半段:再找第 k-(m-i+1)大的数就行

return Search(a, m+1, j, k-(m-i+1));

}

}

int main()

{

int a[7] = { 8,7,6,1,2,3,4 };

int k = 3;

cout << Search(a,2, 6, k);

}

上述问题对应于寻找前K大个数。上述方法对应的数据量比较小,如果N很大,100亿?甚至更多,这个时候数据不能够全部放入内存,所以要求尽可能少遍历数据。不妨设N>K,考虑前K个数中的最大K个数的一个退化的情况:所有K个数就是最大的K个数。如果考虑第K+1个数X呢?如果X比最大的K个数中的最小的数Y小,则最大的K个数保持不变。如果X比最大的K个数中个最小的数Y大,则最大的K个数要除去Y,加入X。如果用一个数组来保存前K大的数,每加入一个数X,就扫描一遍数组。得到数组中最小的数Y,用X代替Y或者保持不变。这种方法消耗的时间O(N*K)

进一步,可以用容量为K的最小堆来存储最大的K个数。最小堆的堆顶元素就是K个数中最小的一个。每次考虑一个数X,如果X比堆顶元素Y小,则保持最小堆不变,因为这个元素比最大的K个数小。如果X

比堆顶元素Y大,那么用X替换原来的堆顶元素Y,X可能破坏原来的最小堆结构(每个结点比它的父节点大),需要更新堆来维持堆的性质。更新堆时间复杂度为O(log2K).总的算法复杂度为O(N*log2k)

1 #include

2 using namespacestd;3 //调整堆

4 void HeapAdjust(int a[],int i,intsize)5 {6 int left = 2 * i + 1;7 int right = 2 * i + 2;8 int min =i;9 if (left < size&&a[left]

19 }20 }21 //建立堆

22 void HeapBuild(int a[],intsize)23 {24 for (int i = size / 2 - 1; i >= 0; i--)25 HeapAdjust(a,i,size);26 }27 //k为需要查找的最大元素个数,size为数组大小,kMax存储k个元素的最小堆

28 void FindMax(int Array[], int k, int size, intkMax[])29 {30 for (int i = 0; i < k; i++)31 kMax[i] =Array[i];32 HeapBuild(kMax,k);33 for (int j = k; j < size; j++)34 {35 if (Array[j] <= kMax[0]) continue;36 kMax[0] =Array[j];37 HeapAdjust(kMax,0,k);38 }39 }40 intmain()41 {42 int a[] = {10,23,17,8,52,35,7,1,28};43 int k = 4;44 int KMax[4] = {0};45 FindMax(a,k,9,KMax);46 for (int i = 0; i < k; i++)47 cout << KMax[i] <

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值