之前写过一个堆及其算法的博客(参考:堆及其算法),但是STL源码考虑的问题很多,所以没有突出堆的核心内容。在此用C++实现了堆。
#include <iostream>
using namespace std;
template <class T>
class heap
{
private:
int m_capacity; //堆的最大容量
int m_n; //第一个空元素的标号
T *m_px; //维护堆的数据
void swap(const int i, const int j)
{
T t=m_px[i];
m_px[i]=m_px[j];
m_px[j]=t;
}
void shiftUp(int i); //!!!这两个内部(私有)函数才是关键!!!
void shiftDown(int i);
public:
heap(int size):m_capacity(size){m_n=0;m_px=new T[size];}
~heap(){delete[] m_px;}
int size(){return m_n;}
void insert(T a);
T popMax();
void makeHeap(T a[],int len);
//void sort();
};
template <class T>
void heap<T>::shiftUp(int i)
{
int t;
while (i>0)
{
t=(i-1)/2;
if (m_px[i]>m_px[t])
{
swap(i,t);
i=t;
}
else break;
}
}
template <class T>
void heap<T>::shiftDown(int i)
{
T temp=m_px[i];
int j=2*i+1;
while(j<m_n)
{
if(j+1<m_n) //存在右子结点
if(m_px[j]<m_px[j+1]) //且右子结点大
j++;
if (temp>=m_px[j]) break;
else
{
m_px[i]=m_px[j];i=j;j=2*i+1;
}
}
m_px[i]=temp;
}
template <class T>
void heap<T>::insert(T a)
{
m_px[m_n++]=a;
shiftUp(m_n-1);
}
template<class T>
void heap<T>::makeHeap(T a[],int len)
{
if (len>m_capacity)
{
cout << "The array is too long!!";
return;
}
for (int i=0;i<len;i++)
{
insert(a[i]);
}
}
template <class T>
T heap<T>::popMax()
{
T t=m_px[0];
m_px[0]=m_px[--m_n];
shiftDown(0);
return t;
}
/*
template <class T>
void heap<T>::sort()
{
int i=m_n-1;
while(m_n>0)
{
swap(0,--m_n);
shiftDown(0);
}
while(i>0)
{
cout<<m_px[i--]<<endl;
}
}*/
int main()
{
int a[10]={9,8,7,6,5,4,2,3,1,0};
heap<int> testheap(20);
testheap.makeHeap(a,10);
for (int i=0;i<10;i++)
{
cout << testheap.popMax() << endl;
}
//testheap.sort();
cout << "finished"<<endl;
return 0;
}
其实这个结构称为优先级队列就更加合适,其中排序操作和测试的部分注释掉了。这个结构有一个缺陷,就是排序一个长度为n的数组,需要额外的n个元素空间,如果只编写一些函数来对数组进行堆操作的话,那么这个n个元素空间的开销可以节省下来。但是这些函数的编写存在一个难点,如何确定一直变化的堆大小,要以参数的形式将堆的大小传入。其实就是一个标号,这个标号确定了,堆和有(无)序区的临界点。