堆(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;
};