双调排序算法Bitonic Sort的实现
双调排序(bitonic sort)属于排序网络(Sorting Network)的一种,是一个可并行计算的排序算法。
Bitonic Sort是一个叫Batcher的数学家在1968年提出的。基础是关于双调序列的Batcher定理。
这个排序算法其实实现起来比较简单(当然我说的是递归实现),但是隐藏在其背后的数学原理就不是那么简单就能说明白的了。在参考了维基百科(http://en.wikipedia.org/wiki/Bitonic_sorter)上面的介绍以及小例子之后,基本明白了这个算法的实现原理。
1、对于一个给定的整形数组A,我们将其均分为两个部分A1,A2;
2、对A1进行升序排序,对A2进行降序排序;
3、将A1和A2进行合并,成为一个升序的数组;
算法的重点在于合并的部分,这其中利用了所谓的Batcher定理。
废话不说了,下面上代码:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 //双调排序类 6 class Bitonic_Sorter 7 { 8 private: 9 int* array;//改造后的输入数组,是真正进行排序处理的数组 10 int* tmp_array;//实际输入的数组 11 int length;//改造后的输入数组的长度 12 int tmp_length;//输入数组的实际长度 13 int gap;//原数组长度和改造后数组长度差值(0或一个正数) 14 bool dire;//排序方式,true为升序 15 int ret_gap(); 16 void transfer(); 17 void bitonic_sort(int lowbundary, int len,bool direction); 18 void bitonic_merge(int lowbundary,int len,bool direction); 19 void compare_and_swap(int i,int j,bool direction); 20 public: 21 Bitonic_Sorter(int arr[],int len); 22 void printData(); 23 void Sorter(bool dir); 24 }; 25 26 //构造函数,完成属性赋值 27 Bitonic_Sorter::Bitonic_Sorter(int arr[],int len) 28 { 29 tmp_array = arr; 30 tmp_length = len; 31 gap = ret_gap(); 32 33 } 34 35 //根据输入数组的长度返回gap的值 36 int Bitonic_Sorter::ret_gap() 37 { 38 double x = (double)log(tmp_length) / log(2);//求log2(length); 39 int z = x + 1; 40 int a = (int)pow(2,z); 41 int b = a - tmp_length;//若length是2^n,则b=0;否则b为其与下一个2^n的差值; 42 if (b == tmp_length) 43 { 44 return 0 ;//说明输入的数组长度满足2^n 45 } 46 else{ 47 return b ;//说明输入的数组长度与2^n相差b 48 } 49 } 50 51 //改造函数,将长度不是2^n的输入数组改造成2^n数组 52 void Bitonic_Sorter::transfer() 53 { 54 if(gap == 0){//输入数组长度满足2^n 55 array = tmp_array; 56 length = tmp_length; 57 } 58 else{ 59 int *temp = new int[tmp_length+gap];//tmp_length+gap即是改造后的数组长度 60 for(int i = 0;i<tmp_length;i++)//完成原数组对新数组的赋值 61 { 62 temp[i] = tmp_array[i]; 63 } 64 for (int j = tmp_length;j<tmp_length+gap;j++)//对新数组的多余部分赋值 65 { 66 if (dire)//升序的话,则填充整型数最大值,不会影响排序及输出,仍取排序后的前tmp_length个数 67 { 68 temp[j] = INT_MAX; 69 } 70 else//降序的话,则填充整型数最小值。 71 { 72 temp[j] = INT_MIN; 73 } 74 } 75 array = temp; 76 length = tmp_length+gap; 77 } 78 } 79 80 //打印改造后的数组,用于排序后输出 81 void Bitonic_Sorter::printData() 82 { 83 for(int i=0;i<tmp_length;i++)//tmp_length才是我们实际需要的排序结果长度 84 { 85 cout<<array[i]<<", "; 86 } 87 } 88 89 //公有排序函数,调用私有函数实现 90 void Bitonic_Sorter::Sorter(bool dir) 91 { 92 dire = dir;//排序方式 93 transfer();//调用改造函数 94 bitonic_sort(0,length,dire); 95 } 96 97 //私有排序函数,递归调用实现 98 void Bitonic_Sorter::bitonic_sort(int lowbundary,int len,bool direction){ 99 if(len>1){ 100 int m=len/2; 101 bitonic_sort(lowbundary,m,direction);//对前半部分进行排序 102 bitonic_sort(lowbundary+m,m,!direction);//后半部分 103 bitonic_merge(lowbundary,len,direction);//两部分组合 104 } 105 } 106 107 //合并函数,递归调用实现 108 void Bitonic_Sorter::bitonic_merge(int lowbundary,int len,bool direction){ 109 if(len>1){ 110 int m=len/2; 111 for(int i=lowbundary;i<lowbundary+m;i++){ 112 compare_and_swap(i,i+m,direction); 113 } 114 bitonic_merge(lowbundary,m,direction);//递归合并前半部分 115 bitonic_merge(lowbundary+m,m,direction);//后半部分 116 } 117 } 118 119 //比较交换函数 120 void Bitonic_Sorter::compare_and_swap(int i, int j,bool direction){ 121 if(direction==(array[i]>array[j])){ 122 swap(array[i],array[j]); 123 } 124 } 125 126 //主函数 127 void main() 128 { 129 int inputarray[1000]; 130 int count = 0; 131 cout<<"Please Input Your Numbers, Each One With An Enter, Finished By Ctrl+Z!"<<endl<<"Start>>"; 132 while (cin>>inputarray[count]) 133 { 134 cout<<"Next>>"; 135 count++; 136 } 137 //以上为输入数组 138 cout<<endl<<"INPUT: 【 "; 139 140 for (int i=0;i<count;i++) 141 { 142 cout<<inputarray[i]<<", "; 143 } 144 cout<<"】"<<endl; 145 //输出输入的数组 146 Bitonic_Sorter bs = Bitonic_Sorter(inputarray,count); 147 bs.Sorter(true); 148 cout<<"OUTPUT IN ASCENDING ORDER: 【 "; 149 bs.printData(); 150 cout<<"】"<<endl; 151 //升序排序 152 bs.Sorter(false); 153 cout<<"OUTPUT IN DESCENDING ORDER: 【 "; 154 bs.printData(); 155 cout<<"】"<<endl; 156 //降序排序 157 system("pause");//等待结束 158 159 }
在编码时参考了http://blog.csdn.net/here1009/article/details/7918185,但是经过实际运行发现它的代码虽然支持任意长度数组排序,但是总是有错。我的代码做了一些修改,即如果数组长度不是2^n,那么我们就将它改造成2^n长度的数组,多出来的部分填充INT_MAX或者INT_MIN,这样的话就不会影响排序结果啦~