加速堆排序的C++实现

加速堆排序比普通堆排序减少了一半的比较次数,但是网上似乎没有加速堆排序的具体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);
}
点赞