堆(heap)又被为优先队列(priority queue)。尽管名为优先队列,但堆并不是队列。回忆一下,在队列中,我们可以进行的限定操作是dequeue和enqueue。dequeue是按照进入队列的先后顺序来取出元素。而在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素。
堆的一个经典的实现是完全二叉树(complete binary tree)。这样实现的堆成为二叉堆(binary heap)。
完全二叉树是增加了限定条件的二叉树。假设一个二叉树的深度为n。为了满足完全二叉树的要求,该二叉树的前n-1层必须填满,第n层也必须按照从左到右的顺序被填满,比如下图:
为了实现堆的操作,我们额外增加一个要求: 任意节点的优先级不小于它的子节点。如果在上图中,设定小的元素值享有高的优先级,那么上图就符合该要求。
已经在排序算法简介及其C++实现中实际使用了堆。堆的主要操作是插入,删除最小元素和排序(元素值本身为优先级键值,小元素享有高优先级)。在插入或者删除排序操作之后,我们必须保持该实现应有的性质: 1. 完全二叉树 2. 每个节点值都小于或等于它的子节点。
我们插入节点2:
插入
删除根节点1。如图:
删除根节点
#pragma once
#include<iostream>
using namespace std;
template <class Type>
class MaxHeap
{
public:
MaxHeap(int sz=DefaultSize)
{
MaxHeapSize=sz>DefaultSize? sz:DefaultSize;
heap=new Type[MaxHeapSize];
memset(heap,0,sizeof(Type)*MaxHeapSize);
CurHeapSize=0;
}
MaxHeap(int *a,int n )
{
MaxHeapSize=n>DefaultSize? n:DefaultSize;
heap=new Type[MaxHeapSize];
memset(heap,0,sizeof(Type)*MaxHeapSize);
CurHeapSize=n;
for(int i=0;i<n;++i)
{
heap[i]=a[i];
}
CreateHeapTree(a,n);
}
void CreateHeapTree(int *a,int n)
{
/* int pos=n/2-1;
while(pos>=0)
{
SiftDown(pos,n);
pos--;
}
*/
int pos=0;
while(pos<=n/2-1)
{
SiftUp(pos,n);
pos++;
}
}
void Show()const
{
for(int i=0; i<CurHeapSize; ++i)
{
cout<<heap[i]<<" ";
}
cout<<endl;
}
void RemoveMax()
{
RemoveMax(CurHeapSize-1);
}
bool Insert(const Type &x)
{
heap[CurHeapSize ]=x;
CurHeapSize++;
CreateHeapTree(heap ,CurHeapSize );
return true;
}
void Sort()
{
int n=CurHeapSize;
int i=1;
while(i<n)
{
if(heap[i]<heap[i+1])
{
swap(heap[i],heap[i+1]);
i--;
}
else
i++;
}
}
protected:
Type RemoveMax(int n)
{
heap[0]=heap[n];
heap[n]=0;
n--;
CreateHeapTree(heap ,n);
CurHeapSize--;
return 0;
}
void SiftDown(int pos,int n )
{
int i=pos,j=2*i+1;
while(j<=n)
{
if(j+1<=n && heap[j]<heap[j+1])
{
j++;
}
if(heap[i] < heap[j])
{
Type tmp = heap[i];
heap[i] = heap[j];
heap[j] = tmp;
}
i = j;
j = 2*i+1;
}
}
void SiftUp(int pos,int n)
{
int i=pos,j=2*i+1;
while(j>0)
{
if(j+1<=n && heap[j]<heap[j+1])
{
j++;
}
if(heap[i]<heap[j])
{
//heap[i]=heap[i]^heap[j];
// heap[j]=heap[i]^heap[j];
// heap[i]=heap[i]^heap[j];
swap(heap[i],heap[j]);
}
j=i;
i=(i-1)/2;
}
}
private:
enum{DefaultSize=10};
Type *heap;
int MaxHeapSize;
int CurHeapSize;
};