加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

数组中求第K大数

发布时间:2020-12-14 03:02:26 所属栏目:大数据 来源:网络整理
导读:问题:有一个大小为n的数组A[0,1,2,…,n-1],求其中第k大的数。 该问题是一个经典的问题,在《算法导论》中被作为单独的一节提出,而且其解决方法很好的利用了分治的思想,将时间复杂度控制在了O(n),这多少出乎我们的意料,此处暂且不表。 该问题还可以变形
问题:有一个大小为n的数组A[0,1,2,…,n-1],求其中第k大的数。

该问题是一个经典的问题,在《算法导论》中被作为单独的一节提出,而且其解决方法很好的利用了分治的思想,将时间复杂度控制在了O(n),这多少出乎我们的意料,此处暂且不表。

该问题还可以变形为:有一个大小为 n的数组A[0,n-1],求其中前k大的数。

一字之差,原问题是“第k大”,变形的问题是“前k大”,但是平均时间复杂度却都可以控制在O(n),这不由得让人暗暗称奇。

?

我们先分析原问题:有一个大小为 n的数组A[0,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的数。

方法一:

方法二:

[cpp]? view plain copy
  1. #include?"iostream"??
  2. using?namespace?std;??
  3. ??
  4. int?random_partion(int?*p,?int?n)??
  5. {??
  6. ?????int?idx=rand()%n;??
  7. ?????swap(p[idx],?p[n-1]);??
  8. int?i=-1;????//i表示最后一个小于p[n-1]的元素的位置??
  9. ?????int?j=0;?????//j用来扫描数组??
  10. ?????for(j=0;?j<n;?j++)??
  11. ?????{??
  12. ????????????//将小于p[n-1]的数交换到前半部分??
  13. ????????????if(p[j]<p[n-1])??
  14. ????????????{??
  15. ????????????????swap(p[++i],?p[j]);??
  16. ????????????}??
  17. ?????}??
  18. ?????swap(p[++i],?p[n-1]);??
  19. ?????return?i;???
  20. }??
  21. int?getMaxK(int?n,87); background-color:inherit; font-weight:bold">int?k)??
  22. ????int?mid;??
  23. if(k<=0)??
  24. ????????????return?-1;??
  25. if(n<k)??
  26. ?????mid=random_partion(p,?n);???//对原数组进行一次划分??
  27. if(mid?==?n-k)??????//如果mid==n-k,那么返回该值,这就是第k大的数??
  28. ?????????return?p[mid];??
  29. else?if(mid<n-k)??
  30. return?getMaxK(p+mid+1,?n-mid-1,?k);??//如果mid<n-k,那么第k大的数在右半数组,而且仍然是第k大数??
  31. else??
  32. return?getMaxK(p,?mid,?k-(n-mid));???//如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数??
  33. int?main(void)??
  34. int?num,a[]?=?{12012,?3,?945,?965,?66,?232,?65,?7,?8,?898,?56,?878,?170,?13,?5};??
  35. ????num=getMaxK(a,?15,?4);??
  36. ????printf("%dn",num);??
  37. ????system("pause");??
  38. ????return?0;??
  39. } ?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读