最小堆的C++实现

原文链接:http://blog.youkuaiyun.com/iqrocket/article/details/8162468


最小堆,即树根的值是最小的,也是一棵完全二叉树。它以层次结构来区分值的大小。并且最小堆可以帮助我们高效地取出具有最小值。它也是实现优先级队列的高效结构。

  1. <span style="font-size:14px;">#include <iostream>  
  2. using namespace std;  
  3.   
  4. int heap[100];  
  5.   
  6. //下滑操作  
  7. void siftDown(int start,int end)  
  8. {  
  9.     //将start号结点向下调整直到end  
  10.     int i=start,j=2*i;  
  11.     heap[0]=heap[i]; //用heap[0]来临时保存i结点的值  
  12.     while(j<=end)  
  13.     {  
  14.         //有右孩子并且右孩子比左孩子小时,将j保存右孩子  
  15.         if(j<end&&heap[j]>heap[j+1]) ++j;  
  16.         //比j号结点小时,不需调整  
  17.         if(heap[0]<=heap[j])   
  18.             break;  
  19.         else  
  20.         {  
  21.             //向下调整  
  22.             heap[i]=heap[j];  
  23.             i=j;  
  24.             j=2*j;  
  25.         }  
  26.     }  
  27.     heap[i]=heap[0];  
  28. }  
  29.   
  30. //生成小根堆  
  31. void createHeap(int n)  
  32. {  
  33.     memset(heap,0,sizeof(heap)); //初始化heap数组  
  34.     cout<<"Enter values:"<<endl;  
  35.     //从下标1开始存  
  36.     for(int i=1;i<=n;++i)  
  37.         cin>>heap[i];  
  38.   
  39.     int currentPos=n/2; //找到开始调整的位置(即最后一个结点双亲的位置)  
  40.     while(currentPos>0)  
  41.     {  
  42.         siftDown(currentPos,n);  
  43.         --currentPos;  
  44.     }  
  45. }  
  46.   
  47. //向上调整的函数  
  48. //将结点start调整到根结点1为止  
  49. void siftUp(int start)  
  50. {  
  51.     int j=start,i=j/2;  
  52.     heap[0]=heap[j];  
  53.     while(j>0)  
  54.     {  
  55.         if(heap[i]<=heap[0])  
  56.             break;  
  57.         else  
  58.         {  
  59.             //向上调整工作  
  60.             heap[j]=heap[i];  
  61.             j=i;  
  62.             i=i/2;  
  63.         }  
  64.     }  
  65.     heap[j]=heap[0];  
  66. }  
  67.   
  68. //插入操作的实现  
  69. bool insert(int x,int& num)  
  70. {  
  71.     ++num;  
  72.     heap[num]=x;  
  73.     siftUp(num);  
  74.       
  75.     return true;  
  76. }  
  77.   
  78. //删除操作  
  79. bool removeMin(int& num)  
  80. {  
  81.     heap[1]=heap[num]; //填补树根  
  82.   
  83.     --num;  
  84.     siftDown(1,num); //将根结点下滑到尾部  
  85.     return true;  
  86. }  
  87.   
  88. //前序遍历  
  89. void preOrder(int i,int num)  
  90. {  
  91.     if(i<=num)  
  92.     {  
  93.         cout<<heap[i]<<" ";  
  94.   
  95.         preOrder(2*i,num);  
  96.         preOrder(2*i+1,num);  
  97.     }  
  98. }  
  99.   
  100. int main()  
  101. {  
  102.     int n=0;  
  103.     cout<<"Enter the num:";  
  104.     cin>>n;  
  105.     createHeap(n);  
  106.     preOrder(1,n);  
  107.     cout<<endl;  
  108.   
  109.     int val=0;  
  110.     cout<<"Enter value to insert:";  
  111.     cin>>val;  
  112.     insert(val,n);  
  113.     preOrder(1,n);  
  114.     cout<<endl;  
  115.   
  116.     removeMin(n);  
  117.     preOrder(1,n);  
  118.     cout<<endl;  
  119. }</span>  

最小堆或者最大堆关键的是siftDown和siftUp函数。它们实现了如何将一棵不符合要求的完全二叉树调整为堆。其中值得一提的是,在将结点值往上或往下移动时,我们并不需要马上将元素值交换来反应移动,因为这样有三次赋值操作。我们只需将待调整的结点放在临时空间中,最终找到结点存放的位置时再将其放在合适的位置。

例如:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值