zoukankan      html  css  js  c++  java
  • 数组中求第K大数

    http://www.10086bank.com/201331813394153.html

    问题:有一个大小为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的数。

    方法一:

    方法二:

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

    ClickCounts: 63  CommentS: 2  
    feifei at 2013-3-18 13:39:04.168 do it

    The Next:镜头焦距和光圈成像自量最优秀的测试(68)

  • 相关阅读:
    MySQL/MariaDB数据库的各种日志管理
    MySQL/MariaDB数据库的事务和隔离级别
    MySQL/MariaDB数据库的并发控制
    MySQL/MariaDB数据库的索引工作原理和优化
    MySQL/MariaDB数据库的查询缓存优化
    安卓(Android)开发基础知识
    typora快捷键
    理解ECS的概念和Unity中的ECS设计
    UGUI合批原理笔记
    SourceTree下载bitbucket代码
  • 原文地址:https://www.cnblogs.com/chinhi/p/3049207.html
Copyright © 2011-2022 走看看