1 堆的定义
堆是一个数组,也是一个近似的完全二叉树(树上的每个结点对应数组中的一个元素,除了最底层外,该树是完全充满的),数组与堆的对应关系如下图所示(在C++中,将下图所有下标减1,本文剩余部分默认初始为0)
图1-1 数组与堆的对应关系
最大堆:所有结点的值均不小于其叶结点;
最小堆:所有结点的值均不大于其叶结点。
2 堆的性质
1) 根据图1-1,对于任意结点的下标i,其父结点、左孩子和右孩子的下标为(注意数组初始下标为0)
int parent(intcurrentID)
{ return (currentID-1) / 2; }
int leftChild(intcurrentID)
{ return 2 * currentID+1; }
int rightChild(intcurrentID)
{ return 2 * currentID+2; }
2) 结点的高度:该结点到叶结点最长简单路径上边的数目;
堆的高度:根结点的高度;对于n个元素的堆,其高度为h=⌊lgn⌋
3)对于n个元素的堆,其叶节点的最小下标为⌊(n+1)/2⌋
3 堆的方法
1)维护最大(小)堆的基本算法
对于一个数组array和一个下标locate,假定以其左孩子和右孩子为根的二叉树都是最大堆,则使得以该结点为根的二叉树为最大堆的算法为
void maxHeapify(int mHarray[],intmHarrayNum,int mHlocate)
{
int mHleftChild, mHrightChild;
int mHlargest;
int mHflag;
mHleftChild= leftChild(mHlocate);
mHrightChild= rightChild(mHlocate);
mHlargest= mHlocate;
if(mHleftChild<= mHarrayNum-1)
mHlargest= mHarray[mHlocate] <mHarray[mHleftChild]? mHleftChild :mHlocate;
if(mHrightChild<= mHarrayNum-1)
mHlargest= mHarray[mHlargest] < mHarray[mHrightChild]? mHrightChild : mHlargest;
if(mHlargest != mHlocate)
{
mHflag= mHarray[mHlocate];
mHarray[mHlocate] =mHarray[mHlargest];
mHarray[mHlargest] = mHflag;
maxHeapify(mHarray, mHarrayNum, mHlargest);
}
}
最小堆的建立算法类似。该算法的时间复杂度为O(h)
2)堆的建立
堆的建立方法为,从下标最大非叶节点开始,逆向调用维护最大堆算法
void buildMaxHeap(int bMHarray[],intbMHarrayNum)
{
for(int i =bMHarrayNum / 2 - 1; i >= 0; i--)
maxHeapify(bMHarray, bMHarrayNum, i);
}
建堆的时间复杂度为O(n)
3)堆排序算法
堆排序算法的基本思想是:建立最大堆,将队首元素与队尾元素进行交换;排除队尾元素,建立最大堆,再将队首元素与次队尾元素进行交换,依此类推。
void heapSort(int hSarray[],inthSarrayNum)
{
int hSnum = hSarrayNum;
int hSflag;
while(hSnum > 1)
{
buildMaxHeap(hSarray, hSnum);
hSflag= hSarray[hSnum - 1];
hSarray[hSnum - 1] = hSarray[0];
hSarray[0] = hSflag;
hSnum--;
}
}
堆排序算法的时间复杂度是O(nlgn),一般情况下其性能差于快速排序。
4 在C++中建立堆
在STL<algorithm.h>,针对堆有如下方法
1)make_heap:建立堆,默认建立最大堆
template<class RandomAccessIterator>
void make_heap (RandomAccessIteratorfirst, RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
void make_heap (RandomAccessIterator first, RandomAccessIterator last,
Compare comp );
2)push_heap:在已建好堆的队尾添加一个元素,再重新构造成一个堆
template<class RandomAccessIterator>
void push_heap (RandomAccessIterator first, RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
void push_heap (RandomAccessIterator first,RandomAccessIterator last,
Compare comp);
3)pop_heap:将堆顶元素放在数组队尾,除过队尾元素,其他元素构成堆
template<class RandomAccessIterator>
void pop_heap (RandomAccessIterator first, RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
void pop_heap (RandomAccessIterator first,RandomAccessIterator last,
Compare comp);
4)sort_heap:对堆进行排序
template<class RandomAccessIterator>
void sort_heap (RandomAccessIterator first, RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
void sort_heap (RandomAccessIterator first,RandomAccessIterator last,
Compare comp);
5)is_heap:判断一个序列是否为堆
template <classRandomAccessIterator>
bool is_heap (RandomAccessIterator first, RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
boolis_heap (RandomAccessIterator first, RandomAccessIterator last,
Compare comp);
6)is_heap_until:判断一个序列中不符合堆要求的第一个元素
template<class RandomAccessIterator>
RandomAccessIterator is_heap_until (RandomAccessIterator first,RandomAccessIterator last);
template<class RandomAccessIterator, class Compare>
RandomAccessIterator is_heap_until (RandomAccessIterator first,
RandomAccessIterator lastCompare comp);
堆的一个例子
template <typenameT>
void vectorPrint(vector<T>vPvector)
{
vector<T>::iterator iElement;
for(iElement = vPvector.begin(); iElement !=vPvector.end();iElement++)
{
cout<< *iElement << "";
}
cout<< endl;
}
int main()
{
int myArray[6] = { 50,44,39,26,71,65 };
vector<int>::iteratoriElement;
vector<int> test(myArray,myArray+5);
cout<< is_heap(test.begin(), test.end()) << endl;
cout<< (is_heap_until(test.begin(), test.end())-test.begin())<< endl;
make_heap(test.begin(),test.end());
vectorPrint(test);
pop_heap(test.begin(),test.end());
test.pop_back();
vectorPrint(test);
test.push_back(99);
push_heap(test.begin(),test.end());
vectorPrint(test);
std::sort_heap(test.begin(),test.end());
vectorPrint(test);
charresponse;
cin>> response;
return 0;
}
5 参考文献
[1] ThomasH.Cormen等著,殷建平等译.算法导论[M].机械工业出版社,2013.
[2] http://www.cplusplus.com/reference/algorithm