• 【数据结构】用堆排序解决TOPK问题


    dca75a869279497689d69523aa1300df.png


    题目名称  TOPK问题

    目录

    题目名称  TOPK问题

    1.题目

    2.题目分析

    3.题目答案

    4.题目知识点

    4.1TOPK

    4.2代码分析



    推荐阅读顺序:

    1.题目->3.答案->2.题目分析->4.题目知识点


    1.题目

    给定一个文件,找出文件中前K个数字,最后打印在屏幕上。

    1. void PrintTopK(const char* filename, int k)
    2. {
    3. }

    2.题目分析

    找前K个最大的?如何处理?

    1.使用堆排序  O(N*logN)

    2.堆选数。

    a.建大堆——————————————————

           相当于选K次即可,如果有数据结构堆就相当于popK次,没有数据结构,就类比于选出最大的数在堆顶然后以此和最后一个元素互换,再向下调整,这样做K次就好,效率为O(N+logN*K)。

            这样做有一个bug,假设N很大,K很小,比如N=100亿 K=100,那么a方法就不行了。

            因为堆必须在内存上申请空间,在N很大的时候,数据在内存上就存储不下了,只能存储在磁盘中。(补充一下:1GB约等于10亿字节)。

    b.建小堆——————————————————

            用前K个数,建K个数的小堆。K+logK*(N-K) 时间复杂度为O(N)空间复杂度为O(K)

            依次遍历后面N-K个数,如果比堆顶数据大,就替换堆顶数据,向下调整进堆。最后堆里面的数据就是最大的前K个。


    3.题目答案

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #include
    4. #include
    5. void swap(int* x, int* y)
    6. {
    7. int z = 0;
    8. z = *x;
    9. *x = *y;
    10. *y = z;
    11. }
    12. void AdjustDown(int *minHeap,int size,int parent)
    13. {
    14. int minchild = parent * 2 + 1;
    15. while (minchild < size)
    16. {
    17. if((minchild+1) minHeap[minchild + 1]))
    18. {
    19. minchild++;
    20. }
    21. if (minHeap[parent] > minHeap[minchild])
    22. {
    23. swap(&minHeap[parent], &minHeap[minchild]);
    24. parent = minchild;
    25. minchild = parent * 2 + 1;
    26. }
    27. else
    28. {
    29. break;
    30. }
    31. }
    32. }
    33. void PrintTopK(const char* filename, int k)
    34. {
    35. assert(filename);
    36. FILE* fp = fopen(filename, "r");
    37. if (fp == NULL)
    38. {
    39. perror("file error\n");
    40. exit(-1);
    41. }
    42. int * minHeap = (int*)malloc(sizeof(int) * k);
    43. if (fp == NULL)
    44. {
    45. perror("file error\n");
    46. exit(-1);
    47. }
    48. for (int i = 0; i < k; i++)
    49. {
    50. fscanf(fp, "%d", &minHeap[i]);
    51. }
    52. for (int parent = (k - 1 - 1) / 2; parent >= 0; parent--)
    53. {
    54. AdjustDown(minHeap,k, parent);
    55. }
    56. int tmp = 0;
    57. while (fscanf(fp, "%d", &tmp) != EOF)
    58. {
    59. if (tmp > minHeap[0])
    60. {
    61. swap(&tmp, &minHeap[0]);
    62. AdjustDown(minHeap, k, 0);
    63. }
    64. }
    65. for (int i = 0; i < k; i++)
    66. {
    67. printf("%d ", minHeap[i]);
    68. }
    69. printf("\n");
    70. //不要忘记free
    71. free(minHeap);
    72. fclose(fp);
    73. }
    74. int main()
    75. {
    76. const char* filename = "D:\\CLASS CODE\\LeetCode\\leet-code-exercise\\力扣练习\\topkdata.txt";
    77. int N = 10000;
    78. int K = 5;
    79. //CreateDataFile(filename, N);
    80. PrintTopK(filename, K);
    81. return 0;
    82. }

    4.题目知识点

    4.1TOPK

    TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。 比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。 对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中,1GB差不多10亿字节)。

    最佳的方式就是用堆来解决,基本思路如下:

    1. 用数据集合中前K个元素来建堆,前k个最大的元素,则建小堆, 前k个最小的元素,则建大堆。

    2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。


    4.2堆排序详解

    简单介绍一下堆排序

    堆排序本质是一种选择排序,找到最大的元素之后要考虑如何选次小的元素。

    堆排序时要利用堆排序本身的优势,它的父子节点的关系。

    如果想看堆排序详解可以移步我的这篇博文:

    (8条消息) 【数据结构】堆排序的实现_vpurple__的博客-CSDN博客https://blog.csdn.net/vpurple_/article/details/126233090?spm=1001.2014.3001.5501


    4.3代码分析

    向下调整函数:

    be481db615ca42f8a3f4c98341c0e2f0.png

     打印TOPK函数:

    3ecfbd1d25db4d6599c875c6ac5a0107.png


     大家好这里是媛仔,欢迎来到媛仔的题目分享栏目,希望篇文章对你能够有所帮助~也希望大家可以找我多多交流,我们下期再见!!

    032d70c368fc479288ef1997c0184c10.jpeg

  • 相关阅读:
    工业4.0利器:MES系统
    [论文总结] 深度学习在农业领域应用论文笔记10
    CSS从入门到精通(4)
    深度学习遥感数据集
    如何使用SQL系列 之 如何在MySQL中使用存储过程
    2627二叉树的层次遍历和之字顺序打印
    《MongoDB》在docker中用得到关于MongoDB一行命令
    【每日一题Day327】LCP 50. 宝石补给 | 模拟
    Android 10.0 11.0 12.0 启动模拟器教程
    Seurat包学习:如何查看R包函数源代码
  • 原文地址:https://blog.csdn.net/vpurple_/article/details/126240375