最近由于需要在GPU上做排序,因为GPU的并行性,所以需要一个并行的排序算法。而BitonicSort双调排序是一个非常适合并行化的排序算法,其在《算法导论》的排序网络一章对其基本原理做了描述与证明。有兴趣大家可以看看。

    作为个人的一个学习总结,这里只是对其性质做些简单介绍,以及它算法基本思想和几个重要的步骤。如果需要了解BitonicSort更加详细的理论证明,可以参考《算法导论》。

    首先BitonicSort的算法复杂度为O(n(logn)^2),看到这里大家会问比快排O(nlogn)要慢啊,干嘛要用它?但是它的n在并行机(比如GPU)上可以并行化掉n,那么复杂度就变为O( (logn)^2 )了,自然比快排等要快。

    下面说下它算法思想和为什么它适合并行化。

    BitonicSort主要算法思想:以有n个元素的0-1数组array递增排序为例。

    第一步:先数组划分成两半,一半是Bitonic递增序列,一半是Bitonic递减序列。Bitonic递增序列可以理解为可以先递增,后递减(也可以只递增),比如:0001110000001111;反之Bitonic递减序列形如111100001111111111111111110000000000000

    第二步:将元素array[i](0<=i<n/2)array[i+n/2]比较

        If(array[i]>array[i+n/2])

          Exchange(array[i],array[i+n/2]);

    然后大家可以简单地证明:数组最小的n/2个元素在前面一半,最大n/2个元素在后面一半。继而不断递归便可得到有序数组。从上面可以看到BitonicSort也存在一个致命的缺点,因为不断的二分,所以原始的BitonicSort只能够排序2^n长度的数组,如何改进下一次再补充。

    为了突出关键,这里只贴出关键部分的代码,其中主要调用SortUp(int beg,int n)这个函数,按照递增排序数组从beg开始的n个元素

int main()

{

BitonicSort biSort;

int n=1<<15;

biSort.InitRandData(n);

biSort.SortUp(0,n);

cout<<"The Sorted Result is:"<<endl;

biSort.OutputArray();

}


void BitonicSort::SortUp(int beg,int n)

{

if(n==1)return;

SortUp(beg,n/2);//把前面的n/2个元素按递增排序

SortDown(beg+n/2,n/2);//把后面n/2个元素按递减排序

MergeUp(beg,n);//合并前面n/2个和后面n/2个数组。

return;

}


void BitonicSort::SortDown(int beg,int n)//类似SortUp,只是按照递减排序数组从beg开始的n个元素

{

if(n==1)return;

SortUp(beg,n/2);

SortDown(beg+n/2,n/2);

MergeDown(beg,n);

}


void BitonicSort::MergeUp(int beg,int n)

{

if(n==1)return;

int halfN=n>>1;

for(int i=beg;i<beg+halfN;i++)

{

if(array[i]>array[i+halfN])Exchange(array[i],array[i+halfN]);

}

MergeUp(beg,halfN);

MergeUp(beg+halfN,halfN);

return;

}

void BitonicSort::MergeDown(int beg,int n)

{

if(n==1)return;

int halfN=n>>1;

for(int i=beg;i<beg+halfN;i++)

{

if(array[i]<array[i+halfN])Exchange(array[i],array[i+halfN]);

}

MergeDown(beg,halfN);

MergeDown(beg+halfN,halfN);

return;

}


posted on 2011-12-20 22:04  Bester  阅读(1703)  评论(0编辑  收藏  举报