大根堆小根堆及其应用

本文介绍了堆的概念及其在解决TopN问题中的应用。包括大根堆与小根堆的实现方法,以及如何通过堆调整算法维持堆的特性。通过实例展示了如何使用小根堆寻找最大N个值,使用大根堆寻找最小N个值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载:http://blog.youkuaiyun.com/pngynghay/article/details/22052737


堆的概念

堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:
Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]
即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。
堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

其中,大根堆和小根堆在海量数据的top N问题中,有着很好的时间复杂度。

首先,先给出一个交换两个变量数值的函数。

[cpp]  view plain  copy
  1. void Swap(uint32_t* array, uint32_t i, uint32_t j)  
  2. {  
  3.     assert(array);  
  4.     uint32_t tmp = 0;  
  5.     tmp = array[j];  
  6.     array[j] = array[i];  
  7.     array[i] = tmp;  
  8. }  

头文件包含

[cpp]  view plain  copy
  1. #include <stdlib.h>  
  2. #include <stdint.h>  
  3. #include <assert.h>  
  4. #include <string.h>  
  5. #include <stdio.h>  

大根堆实现

[cpp]  view plain  copy
  1. /*大根堆调整*/  
  2. void MaxHeapify(uint32_t* array, uint32_t heapSize, uint32_t currentNode)  
  3. {  
  4.     uint32_t leftChild = 0, rightChild = 0,  largest = 0;  
  5.     leftChild = 2*currentNode + 1;  
  6.     rightChild = 2*currentNode + 2;  
  7.     if(leftChild < heapSize && array[leftChild] > array[currentNode])  
  8.         largest = leftChild;  
  9.     else  
  10.         largest = currentNode;  
  11.     if(rightChild < heapSize && array[rightChild] > array[largest])  
  12.         largest = rightChild;  
  13.     if(largest != currentNode)  
  14.     {  
  15.         Swap(array, largest, currentNode);  
  16.         MaxHeapify(array, heapSize, largest);  
  17.     }  
  18. }  
  19.   
  20. /*构建大根堆*/  
  21. void MaxHeapCreat(uint32_t* array, uint32_t heapSize)  
  22. {  
  23.     int i = 0;  
  24.     for(i = heapSize/2; i >= 0; i--)  
  25.     {  
  26.         MaxHeapify(array, heapSize, i);  
  27.     }  
  28. }  

小根堆实现

[cpp]  view plain  copy
  1. /*小根堆调整*/  
  2. void MinHeapify(uint32_t* array, uint32_t heapSize, uint32_t currentNode)  
  3. {  
  4.     uint32_t leftChild = 0, rightChild = 0,  minimum = 0;  
  5.     leftChild = 2*currentNode + 1;  
  6.     rightChild = 2*currentNode + 2;  
  7.     if(leftChild < heapSize && array[leftChild] < array[currentNode])  
  8.         minimum = leftChild;  
  9.     else  
  10.         minimum = currentNode;  
  11.     if(rightChild < heapSize && array[rightChild] < array[minimum])  
  12.         minimum = rightChild;  
  13.     if(minimum != currentNode)  
  14.     {  
  15.         Swap(array, minimum, currentNode);  
  16.         MinHeapify(array, heapSize, minimum);  
  17.     }  
  18. }  
  19. /*构建小根堆*/  
  20. void MinHeapCreat(uint32_t* array, uint32_t heapSize)  
  21. {  
  22.     int i = 0;  
  23.     for(i = heapSize/2; i >= 0; i--)  
  24.     {  
  25.         MinHeapify(array, heapSize, i);  
  26.     }  
  27. }  

 

top N问题

利用小根堆解决获取大量数据中最大的N个值,先构建一个拥有N个元素的小根堆。然后,将其余的元素插入到小根堆即可。插入方法如下:

[cpp]  view plain  copy
  1. /*maintain the top N numbers*/  
  2. void MinInsert(uint32_t* array, uint32_t heapSize, uint32_t elem)  
  3. {  
  4.     if(elem > array[0])  
  5.     {  
  6.         array[0] = elem;  
  7.         MinHeapify(array, heapSize, 0);  
  8.     }  
  9. }  


利用大根堆解决获取大量数据中最小的N个值,先构建一个拥有N个元素的大根堆。然后,将其余的元素插入到大根堆即可。插入方法如下:

[cpp]  view plain  copy
  1. /*maintain the low N numbers*/  
  2. void MaxInsert(uint32_t* array, uint32_t heapSize, uint32_t elem)  
  3. {  
  4.     if(elem < array[0])  
  5.     {  
  6.         array[0] = elem;  
  7.         MaxHeapify(array, heapSize, 0);  
  8.     }  
  9. }  

时间复杂度分析

堆调整一次的时间复杂度是O(logN)。所以,通过堆来解决top N 问题的时间复杂度是O(nlogN).

其中,n为数据的个数,N为堆维护的数据的个数。

 

测试程序

[cpp]  view plain  copy
  1. int main()  
  2. {  
  3.     int i = 0, heapSize = 10;  
  4.     uint32_t array[] = {2,20,13,18,15,8,3,5,4,25};  
  5.     uint32_t minelem = 10, maxelem = 1;  
  6.   
  7. /*build min heap and test insert*/  
  8.     MinHeapCreat(array, heapSize);    
  9.     printf("Output the MinHeap:\n");    
  10.     for(i = 0; i < heapSize; i++)    
  11.     {    
  12.         printf("%d\t", array[i]);    
  13.     }    
  14.     MinInsert(array, heapSize, minelem);   
  15.     printf("\nOutput insert elem %d:\n",minelem);  
  16.     for(i = 0; i < heapSize; i++)  
  17.     {  
  18.         printf("%d\t", array[i]);  
  19.     }  
  20.     printf("\n");  
  21. /*build max heap and test insert*/  
  22.     MaxHeapCreat(array, heapSize);      
  23.     printf("Output the MaxHeap:\n");      
  24.     for(i = 0; i < heapSize; i++)      
  25.     {      
  26.         printf("%d\t", array[i]);      
  27.     }      
  28.     MaxInsert(array, heapSize,maxelem);   
  29.     printf("\nOutput insert elem %d:\n",maxelem);      
  30.     for(i = 0; i < heapSize; i++)      
  31.     {      
  32.         printf("%d\t", array[i]);      
  33.     }  
  34.     printf("\n");   
  35. }  

测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值