【数据结构与算法】堆的应用:堆排序和topk问题

简介: 【数据结构与算法】堆的应用:堆排序和topk问题

一.堆排序

我们知道冒泡算法的时间复杂度是O(N^2),在数据量很多的时候,N^2是个很可怕的数字,二分算法的时间复杂度是O(logn),但是二分算法有限制条件,实用性并不高,那怎样才能高效实用的排序呢?

堆排序就能很好解决上述问题,堆排序的时间复杂度是O(logn),也没啥限制条件,可以实现高效排序。

这里要注意,排升序要建大堆,排降序要建小堆;

1.假设排升序,所以建大堆;

2.堆建好后,定义一个 end 变量,令其 =n-1(数组最后一个元素的下标是n-1)

3.堆建好后,数组第一个元素就是最大的,将其与最后一个数据交换,然后这个数据就不需要动了,为了保持它是个大堆,让它的前 end-1 个元素向下调整,然后end--,当 end<=0 时就结束循环

 

堆排序不需要手搓个堆,只需要用到向下调整这个函数,所以使用堆排序时,只需写个向下调整就行了。

1. void Swap(int* p1, int* p2)
2. {
3.  int tmp = *p1;
4.  *p1 = *p2;
5.  *p2 = tmp;
6. }
7. void AdjustDown(int* arr, int parent, int n)
8. {
9.  assert(arr);
10.   int child = 2 * parent + 1;
11.   while (child < n)
12.   {
13.     if ((child + 1) < n&& arr[child + 1] > arr[child])
14.     {
15.       child++;
16.     }
17. 
18.     if (arr[child] > arr[parent])
19.     {
20.       Swap(&arr[child], &arr[parent]);
21.       parent = child;
22.       child = 2 * parent + 1;
23.     }
24.     else
25.       break;
26.   }
27. }
28. void Heapsort(int* arr, int n)
29. {
30.   assert(arr);
31.   int i = 0;
32.   for (i = (n - 2) / 2; i >= 0; i--)   //建堆
33.   {
34.     AdjustDown(arr, i, n);
35.   }
36.   int end = n - 1;
37.   while (end)
38.   {
39.     Swap(&arr[0], &arr[end]);
40. 
41.     AdjustDown(arr, 0, end);
42. 
43.     end--;
44.   }
45.   for (i = 0; i < n; i++)
46.   {
47.     printf("%d  ", arr[i]);
48.   }
49.   printf("\n");
50. }

二.topk问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

基本思路如下:

1. 用数据集合中前K个元素来建堆,注意:

  前k个最大的元素,则建小堆;

  前k个最小的元素,则建大堆;

2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素;

3.将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

我们可以从文件中读取数据,这样的实用性更高些;

假设找的是最大的前k个数据,所以建小堆;

具体:

1.创建一个k个元素的数组,模拟建堆,从文件中读取k个数据存入数组中;

2.从文件中取数据与数组的第一个元素比较,也就是堆顶的数据,因为是小堆,如果该数据比堆顶数据大,则将值赋给堆顶,成为新的堆顶,不用担心会出什么问题,因为是小堆,所以那些大的数据会往下沉,如果不大于堆顶的数据,则继续从文件中取数据出来比较;

3.当读取文件结束时就结束循环

如果对文件操作不太熟悉的话,可参考->文件的基础操作

如要想检验你写的代码是否能解决topk问题时,可以在数据创建完成后,手动修改文件中的k个数据,如果是找最大的k个数据,那么只需要修改k个数据,且每个都大于原来文件的最大值,这样在测试代码时,输出的就是你修改的k个数据。

1. void Createdata(const char file,int n)   //创建数据
2. {
3.  int i = 0;
4.  int x = 0;
5.  FILE* fin = fopen("file", "w");  //打开文件
6.  if (fin == NULL)
7.  {
8.    perror("fopen fail");
9.    exit(-1);
10.   }
11.   for (i = 0; i < n; i++)
12.   {
13.     x = rand() % 100 + 1;   //利用随机数生成函数,创建k个范围在1~100之间的数据
14.     fprintf(fin, "%d\n", x);  //将数据写入文件中
15.   }
16.   fclose(fin);  //关闭文件
17.   fin = NULL;
18. }
19. 
20. void topk(const char file, int k)
21. {
22.   FILE* fout = fopen("file", "r");
23.   if (fout == NULL)
24.   {
25.     perror("fopen fail");
26.     exit(-1);
27.   }
28.   HPdatatype* arr = (HPdatatype*)malloc(sizeof(HPdatatype) * k);
29.   if (arr == NULL)
30.   {
31.     perror("malloc fail");
32.     exit(-1);
33.   }
34.   int i = 0;
35.   for (i = 0; i < k; i++)
36.   {
37.     fscanf(fout, "%d", &arr[i]);  //从文件中写入k个数据到数组中,模拟堆的创建
38.   }
39. 
40.   int val = 0, ret = 0;
41.   ret = fscanf(fout, "%d", &val);   //从文件中取数据
42.   while (ret != EOF)
43.   {
44.     if (val > arr[0])  //将取出的数据与堆顶数据比较,若大于,则其成为新的堆顶
45.     {
46.       arr[0] = val;
47.       AdjustDown(arr, 0, k);   //向下调整,保持小堆或是大堆
48.     }
49. 
50.     ret = fscanf(fout, "%d", &val);  //从文件中取数据
51.   }
52.   free(arr);
53.   fclose(fout);
54.   arr = NULL;
55.   fout = NULL;
56. 
57. }
58. 
59. int main()
60. {
61.   srand((unsigned int)time(NULL));
62.   const char file = "data.txt";
63.   int n = 1000;
64.   int k = 10;
65.   //Createdata(file,n);
66.   topk(file, k);
67.   return 0;
68. }

🐬🤖本篇文章到此就结束了,若有错我或是建议的话,欢迎小伙伴们指出;🕊️👻

😄😆希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;🥰🤩

😍😁谢谢你的阅读。😸😼


目录
相关文章
|
3月前
|
存储 Java
Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
56 1
|
3月前
|
存储 算法 C语言
通义灵码在考研C语言和数据结构中的应用实践 1-5
通义灵码在考研C语言和数据结构中的应用实践,体验通义灵码的强大思路。《趣学C语言和数据结构100例》精选了五个经典问题及其解决方案,包括求最大公约数和最小公倍数、统计字符类型、求特殊数列和、计算阶乘和双阶乘、以及求斐波那契数列的前20项和。通过这些实例,帮助读者掌握C语言的基本语法和常用算法,提升编程能力。
95 4
|
3月前
|
机器学习/深度学习 存储 人工智能
数据结构在实际开发中的广泛应用
【10月更文挑战第20天】数据结构是软件开发的基础,它们贯穿于各种应用场景中,为解决实际问题提供了有力的支持。不同的数据结构具有不同的特点和优势,开发者需要根据具体需求选择合适的数据结构,以实现高效、可靠的程序设计。
212 63
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
71 5
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
65 1
|
2月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
46 5
|
3月前
探索数据结构:队列的的实现与应用
探索数据结构:队列的的实现与应用
|
11天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
145 80
|
5天前
|
机器学习/深度学习 算法
基于遗传优化的双BP神经网络金融序列预测算法matlab仿真
本项目基于遗传优化的双BP神经网络实现金融序列预测,使用MATLAB2022A进行仿真。算法通过两个初始学习率不同的BP神经网络(e1, e2)协同工作,结合遗传算法优化,提高预测精度。实验展示了三个算法的误差对比结果,验证了该方法的有效性。
|
7天前
|
机器学习/深度学习 数据采集 算法
基于PSO粒子群优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目展示了基于PSO优化的CNN-GRU-SAM网络在时间序列预测中的应用。算法通过卷积层、GRU层、自注意力机制层提取特征,结合粒子群优化提升预测准确性。完整程序运行效果无水印,提供Matlab2022a版本代码,含详细中文注释和操作视频。适用于金融市场、气象预报等领域,有效处理非线性数据,提高预测稳定性和效率。