加速堆排序的C++实现

来源:互联网 发布:电饭煲推荐 知乎 编辑:程序博客网 时间:2024/06/15 09:07

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