当前位置:   article > 正文

【数据结构—堆排序、top k问题和时间复杂度】_topk堆排序平均时间复杂度

topk堆排序平均时间复杂度

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

一、堆排序(升序)

实现数组的排序:

方法一:利用堆来实现排序的话,但是realloc()函数来申请空间。

方法二:我们可以把一个现有数组直接建堆,可以不用申请额外的空间,直接在数组这个结构上直接动手。

1.1向上调整算法:

1.2向下调整算法:

1.3、堆排序的实现:

升序:要建大堆先选出最大的数,然后把首位的值一交换,相当于最后一个数排好了,那最后一个数就不要动了,可以把最后一个数不在看作堆内的数据,此时堆的左、右子树还是堆的形式,我们便把堆的首位数向下调整,我们便可以得到第二位最大的数,我们再次首位的值交换,然后把第二位最大的数也排除堆的范围之内;循环往复。
时间复杂度:(一次建堆:1*LogN;选数:(N-1)*LogN)
(为什么不用小堆呢?小堆的话,只能选出最小的数,但如何选出次小的数呢?
如果我们取出最小的数,剩下的数可能是堆,也可能不是堆;若把剩下的数看成堆,那么关系全乱了(兄弟和叔侄之间没有大小关系),所以我们只能把剩下的数重新建堆,代价是:每建一次堆的时间复杂度为:O(LogN),这个方法不好)

时间复杂度:算的是量级,有时候时间复杂度是一样的,但是他们的效率是不一样的,在性能上是有差异的。

二、top k问题

top k问题:N个数里面找最大的前k个(N远大于k)
思路1:

N个数插入到大堆里面,Pop K次。
时间复杂度:一个数插入最多是高度次:LogN;N个数插入是:N*LogN次;取K个数是:K*LogN次,最终是O(N*LogN)。
思路2:

1、读取前K个值,建立k个数的小堆;
2、依次在读取后面的值,跟堆顶比较,如果比堆顶大,就替换堆顶的值,进堆,再向下调整。

2.1top k问题的代码实现:

  1. //创造通过的随机数
  2. void GreateNDate()
  3. {
  4. //造数据
  5. int n = 10000000;
  6. srand(time(0));
  7. const char* file = "data.txt";
  8. //以写的形式将文件打开
  9. FILE* fin = fopen(file, "w");
  10. //fin:写 fout:读
  11. if (fin == NULL)
  12. {
  13. perror("fopen error");
  14. return;
  15. }
  16. for (int i = 0; i < n; i++)
  17. {
  18. //我们产生一千万个数,直接用rand()是不行的
  19. //因为库里面的随机数最多只能产生三万多个,所以会有997万个数是重复的;
  20. //我们给rand()+i会大大减小重复
  21. int x = (rand() + i) % 10000000;
  22. fprintf(fin, "%d\n", x);//写入文件中
  23. }
  24. fclose(fin);
  25. }
  26. //找出top k中最大的前k个数据
  27. void PrintTopK(const char* file, int k)
  28. {
  29. //以读的形式将文件打开
  30. FILE* fout = fopen(file, "r");
  31. if (fout == NULL)
  32. {
  33. perror("fopen error");
  34. return;
  35. }
  36. //建一个k个数的小堆
  37. int* minheap = (int*)malloc(sizeof(int) * k);
  38. if (minheap == NULL)
  39. {
  40. perror("malloc error");
  41. return;
  42. }
  43. //读取前k个,建小堆
  44. for (int i = 0; i < k; i++)
  45. {
  46. fscanf(fout, "%d", &minheap[i]);
  47. AdjustUp(minheap, i);
  48. }
  49. int x = 0;
  50. //把文件中的数据读取出来到x中
  51. while (fscanf(fout, "%d", &x) != EOF)
  52. {
  53. //剩下的数与小堆的堆顶进行比较,并把大的数替换
  54. if (x > minheap[0])
  55. {
  56. minheap[0] = x;
  57. AdjustDown(minheap, k, 0);
  58. }
  59. }
  60. for (int i = 0; i < k; i++)
  61. {
  62. printf("%d ", minheap[i]);
  63. }
  64. printf("\n");
  65. fclose(fout);
  66. }
  67. int main()
  68. {
  69. //GreateNDate();
  70. PrintTopK("data.txt", 3);
  71. return 0;
  72. }

 2.2如何保证取出的前k个数就是N个数里面最小的前k个数呢?

我们把随机数都取模1000万,那么随机数都是1000万以内的值;我们挑10个随机位置,该它们的值,让他们的值都大于1000万;那也就意味着随便改这10个位置,都能够把它们的值取出来,就说明取出的是前k个值是最大的,如果取不出来,那就是有问题的。

2.3实际数据测试展示:

三、时间复杂度

时间复杂度:算的是量级,有时候时间复杂度是一样的,但是他们的效率是不一样的,在性能上是有差异的。


总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/716791
推荐阅读
相关标签
  

闽ICP备14008679号