加速堆排序比普通堆排序减少了一半的比较次数,但是网上似乎没有加速堆排序的具体C++实现,这里参照《计算机算法——设计与分析导论》(BG)给出AcceleratedHeapSort的C++实现,通过了OJ上面的测试,如果有可以优化或者需要改进的地方请多多指教。(其中被注释掉的代码用于输出调试信息)
#include <iostream>
#include <cmath>
using namespace std;
/* 输出数组 */
void print(int *ar, int n)
{
for(int i=0;i<n;i++)
cout << ar[i] << " ";
cout << endl;
}
/* 普通堆排序的fixHeap函数,建堆时需要用到 */
void fixHeap(int *ar, int heapSize, int root, int K)
{
int left = 2*root+1;
int right = 2*root+2;
if(left>heapSize-1) //判断root是否为叶子节点
ar[root] = K;
else
{
int largerSubHeap;
if(left==heapSize-1) //无右子树
largerSubHeap = left;
else if(ar[left]>ar[right]) //左子树较大
largerSubHeap = left;
else //右子树较大
largerSubHeap = right;
if(K>=ar[largerSubHeap]) //若K比最大子树根的值大,则直接插入
ar[root] = K;
else //若K没有最大子树根的值大,则将K向下移动
{
ar[root] = ar[largerSubHeap];
fixHeap(ar,heapSize,largerSubHeap,K);
}
}
}
/* 建堆 */
void constructHeap(int *ar, int heapSize, int root)
{
int left = 2*root+1;
int right = 2*root+2;
if(left>heapSize-1) //判断root是否为叶子节点
return;
else
{
constructHeap(ar,heapSize,left); //左子树
constructHeap(ar,heapSize,right); //右子树
fixHeap(ar,heapSize,root,ar[root]); //向下调整
}
}
/* 下降到hStop高度,返回hStop高度对应的空位,hStop一般设置为原先高度的1/2 */
int promote(int *ar, int hStop, int root, int h)
{
int vacStop;
int left = root*2+1; //左子女
int right = root*2+2; //右子女
if(h<=hStop) //高度已经降到了预先设定的高度hStop
vacStop = root;
else if(ar[right]>=ar[left])
{
ar[root] = ar[right];
vacStop = promote(ar,hStop,right,h-1);
}
else
{
ar[root] = ar[left];
vacStop = promote(ar,hStop,left,h-1);
}
return vacStop;
}
/* 将空位从vacant向上移动,合适的时候停下来,不合适继续向上,直到root */
void bubbleUpHeap(int *ar, int root, int K, int vacant)
{
if(vacant==root)
ar[vacant] = K;
else
{
int parent = (vacant-1)/2;
if(K<ar[parent]) //合适则放置K
ar[vacant] = K;
else //不合适则将parent结点向下移动,继续向上寻找合适的位置
{
ar[vacant] = ar[parent];
bubbleUpHeap(ar,root,K,parent);
}
}
}
/* 加速堆排序的核心函数 */
void fixHeapFast(int *ar, int K, int root, int h, int heapSize)
{
if(h==0)
ar[root] = K;
else if(h==1) //类似fixHeap的处理
{
int left = root*2+1;
int right = root*2+2;
if(left>heapSize-1) //若left超出了heapSize,则直接将K赋给root并返回
{
ar[root] = K;
return;
}
int largerSubHeap;
if(left==heapSize-1) //无右子树
largerSubHeap = left;
else if(ar[left]>ar[right]) //左子树较大
largerSubHeap = left;
else //右子树较大
largerSubHeap = right;
//cout << " root=" << root << ",K=" << K << ",largerSubHeap=" << largerSubHeap << endl;
if(K>=ar[largerSubHeap]) //若K比最大子树根的值大,则直接插入
ar[root] = K;
else //若K没有最大子树根的值大,则将K向下移动
{
ar[root] = ar[largerSubHeap];
ar[largerSubHeap] = K;
//cout << " ";
//print(ar,heapSize);
}
}
else
{
int hStop = h/2;
int vacStop = promote(ar,hStop,root,h); //高度为h/2处空位所在位置
int vacParent = vacStop/2;
if(K>=ar[vacParent]) //若K大于当前空位的父结点,则父结点下移,K向上移动;root结点本身不移动
{
ar[vacStop] = ar[vacParent];
bubbleUpHeap(ar,root,K,vacParent);
}
else
fixHeapFast(ar,K,vacStop,hStop,heapSize);
}
}
/* 加速堆排序的接口函数 */
void accelHeapSort(int *ar, int n)
{
constructHeap(ar,n,0);
//cout << "constructed: ";
//print(ar,n);
for(int heapSize=n-1;heapSize>0;heapSize--)
{
int K = ar[heapSize];
ar[heapSize] = ar[0];
fixHeapFast(ar,K,0,log10(heapSize)/log10(2),heapSize);
//print(ar,n);
}
}
int main()
{
int n;
cin >> n;
int *p = new int [n];
for(int i=0;i<n;i++)
cin >> p[i];
accelHeapSort(p,n);
print(p,n);
}