各种排序方法的收集

各种排序算法实现的收集,肯定有你没有见过的。

归并,快排,奇偶排,cocktail 排序, 梳排序,计数排序,基数排序,LSD基数排序, shell排序,桶排序,鸽巢排序等 

1. 归并排序的实现

#include <iostream>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
using namespace std;
void merage(int a[],int low,int mid,int high)
{
int *temp = (int *)malloc((high - low + 1) * sizeof(int));
int begin1 = low;
int end1 = mid;
int begin2 = mid + 1;
int end2 = high;
int k;
for( k = 0;begin1 <= end1 && begin2 <= end2; k ++)
if(a[begin1] <= a[begin2])
temp[k]
= a[begin1 ++];
else
temp[k]
= a[begin2 ++];

if(begin1 <= end1)
memcpy(temp
+ k,a+begin1,(end1-begin1+1)*sizeof(int));
if(begin2 <= end2)
memcpy(temp
+ k,a + begin2,(end2-begin2+1)*sizeof(int));

memcpy(a
+low, temp, (high-low+1)*sizeof(int));//将排序好的序列拷贝回数组中
}
void merage_sort(int a[],int frist,int last)
{
int mid = 0;
if(frist < last)
{
//mid = (frist+last) / 2; 可能是产生溢出
//mid = frist /2 + last / 2;
mid = (frist & last) + ((frist ^ last) >> 1);
merage_sort(a,frist,mid);
merage_sort(a,mid
+ 1,last);
merage(a,frist,mid,last);
}
}
int main()
{
int a[20] = {1,4,5,6,7,8,9,15,16,17,18,12,13,14,19,2,3,10,11,0};
merage_sort(a,
0,20);
for(int i = 0;i < 20; i ++)
cout
<< a[i] << " ";
cout
<< endl;
return 0;
}

  2. 快排实现

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

  

#include <iostream>
using namespace std;
#define N 100
int partition(int r[],int low,int high)
{
int key;
key
= r[low];//这里选择数组的第一个元素作为基准点
while(low < high)
{
while(low < high && r[high] >= key) high --;
r[low]
= r[high];
while(low < high && r[low] <= key) low ++;
r[high]
= r[low];
}
r[low]
= key;//左边比它小,右边比它大
return low;
}
void quickSort(int r[],int low,int high)
{
int k;
if(low < high)
{
k
= partition(r,low,high);
quickSort(r,low,k
- 1);
quickSort(r,k
+1,high);
}
}
int main()
{
int a[10] = {1,7,6,8,9,3,5,4,2,0};
quickSort(a,
0,9) ;
for(int i = 0;i < 10;i ++)
cout
<< a[i] << " ";
cout
<< endl;
return 0;
}

  

 3 奇偶排序法

 

#include <iostream>

using namespace std;
/*
奇偶排序法的思路是在数组中重复两趟扫描。
第一趟扫描选择所有的数据项对,
a[j]和a[j+1],j是奇数(j=1, 3, 5……)。
如果它们的关键字的值次序颠倒,
就交换它们。
第二趟扫描对所有的偶数数据项进行同样的操作(j=2, 4,6……)。
重复进行这样两趟的排序直到数组全部有序。
*/
/*
 奇偶排序实际上在多处理器环境中很有用,
处理器可以分别同时处理每一个奇数对,
然后又同时处理偶数对。
因为奇数对是彼此独立的,
每一刻都可以用不同的处理器比较和交换。
这样可以非常快速地排序。
*/
void swap(int a[],int a1,int a2)
{
int temp = a[a1];
a[a1]
= a[a2];
a[a2]
= temp;
}
void oddEvenSort(int a[],int n)
{
int flag = 1;
while(flag != 0)
{
flag
= 0;
for(int i = 1;i < n-1;i += 2)
{
if(a[i] > a[i + 1])
{
swap(a,i,i
+ 1);
flag
++;
}
}
for(int i = 0;i < n-1;i += 2)
{
if(a[i] > a[i + 1])
{
swap(a,i,i
+ 1);
flag
++;
}
}
}
}
int main()
{
int a[10] = {1,2,0,9,6,8,7,3,4,5} ;
oddEvenSort(a,
10);

for(int i = 0;i < 10;i ++)
cout
<< a[i] << " ";
cout
<< endl;
return 0;
}

 4 cocktail 排序,是冒泡排序的一种变形。与冒泡排序的不同处在于排序时是以双向在序列中进行排序,然后以一个是否交换作为排序结束的标志

#include <iostream>
using namespace std;
void cocktail_sort(int arr[],int n)
{
int left = 0;
int right = n - 1;
bool swapped = true;
while(swapped)
{
swapped
= false;
for(int i = left; i < right; i ++)
{
if(arr[i] > arr[i + 1])
swap(arr[i],arr[i
+1]);
swapped
= true;
}
right
-= 1;
for(int i = right; i > left; i --)
{
if(arr[i] < arr[i-1])
{
swap(arr[i],arr[i
- 1]);
swapped
= true;
}
}

left
+= 1;

}
}
////////////////////////////////////////////////////////
int main()
{
int a[10] = {1,2,0,9,6,8,7,3,4,5} ;
cocktail_sort(a,
10);

for(int i = 0;i < 10;i ++)
cout
<< a[i] << " ";
cout
<< endl;
return 0;
}

  5. comb_sort 又叫三路划分快排,gap 选取一般是1.3,但根据统计,对于随机数据1.247330950103979更加合适,这个数根据e得来的 梳排序,改良自冒泡排序和快速排序

     在泡沫排序中,只比较阵列中相邻的二项,即比较的二项的间距(Gap)是1,梳排序提出此间距其实可大于1,改自插入排序希尔排序同样提出相同观点。梳排序中,开始时的间距设定为阵列长度,并在循环中以固定比率递减,通常递减率设定为1.3。在一次循环中,梳排序如同泡沫排序一样把阵列从首到尾扫描一次,比较及交换两项,不同的是两项的间距不固定于1。如果间距递减至1,梳排序假定输入阵列大致排序好,并以泡沫排序作最后检查及修正。

#include <iostream>
using namespace std;
void comb_sort(int a[],int n)
{
float shrink_factor = 1.247330950103979;
int gap = n,swapped = 1,temp,i;
while((gap > 1) || swapped )
{
if(gap > 1)
gap
= gap / shrink_factor;

swapped
= 0;
i
= 0;
while ((gap + i ) < n)
{
if(a[i] > a[i + gap])
{
temp
= a[i];
a[i]
= a[i + gap];
a[i
+ gap] = temp;
}
i
++;
}
}
}
int main()
{
int a[10] = {2,3,5,6,9,8,7,0,4,1};
comb_sort(a,
10);
for(int i = 0;i < 10; i ++)
cout
<< a[i] << " ";
cout
<< endl;
return 0;
}

  6. 计数排序 对每一个输入元素x,确定出小于x的元素个数。适用于输入是由小范围的整数构成的序列。算法是稳定的。

#include <iostream>
using namespace std;
int arr[100], res[100], hash[100];
int len, k = -1;
void PrintHash()
{
cout
<< "Hash数组: " << endl;
for(int i=0; i<=k; ++i)
cout
<< hash[i] << " ";
cout
<< endl;
}
void countingSort()
{
for(int i=0; i<=k; ++i)
hash[i]
= 0;
// 此过程记录每一个元素的个数
for(int i=1; i<=len; ++i)
++hash[arr[i]];
PrintHash();
// 此过程确定小于x的元素的个数
for(int i=1; i<=k; ++i)
hash[i]
+= hash[i-1];
PrintHash();
// 思考这里为何从i=len开始?而不从i=1开始?
for(int i=len; i>0; --i)
{
res[hash[arr[i]]]
= arr[i];
--hash[arr[i]];
}
}
int main()
{
cout
<< "输入元素个数: ";
cin
>> len;
cout
<< "输入" << len << "个元素: " << endl;
for(int i=1; i<=len; ++i)
{
cin
>> arr[i];
if(k < arr[i])
k
= arr[i];
}
countingSort();
cout
<< "排序后结果为: " << endl;
for(int i=1; i<=len; ++i)
cout
<< res[i] << " ";    
cout
<< endl;
}

  7. 基数排序  按组成关键字的各个位来进行排序

#include <iostream>
#include
<string.h>
using namespace std;

int arr[100],res[100],hash[100];

int n;
int maxbit()
{
int max = 0;
int temp[100];

for(int i = 0;i < n; i ++)
temp[i]
= arr[i];

for(int i = 0;i < n;i ++)
{
int t = 1;
while(temp[i]/10 > 10)
{
t
++;
temp[i]
/= 10;
}
if(max < t)
max
= t;
}


cout
<< "max:" << max << endl;
return max;
}


void radixSort()
{
memset(res,
0,sizeof(res));
int nbit = maxbit();

int tmp;
int radix = 1;
for(int i = 1;i <= nbit;i ++)
{
for(int j = 0;j < 10;j ++)
hash[j]
= 0;
for(int j = 0;j< n;j ++)
{
tmp
= (arr[j] / radix) % 10;
++hash[tmp];
}

for(int j = 1;j < 10;j ++)
hash[j]
+= hash[j - 1];

for(int j = n - 1;j >= 0;j --)
{
tmp
= (arr[j]/radix) % 10;
-- hash[tmp];
res[hash[tmp]]
= arr[j];
}

for(int j = 0;j < n;j ++)
arr[j]
= res[j];
radix
*= 10;
}
}
int main()
{
cout
<< "输入元素个数:" << endl;
cin
>> n;
cout
<< "输入" << n << "个元素:" << endl;

for(int i = 0;i < n;i ++)
cin
>> arr[i];

radixSort();

cout
<< "排序后:" << endl;

for(int i = 0;i < n; i ++)
cout
<< res[i] << " ";
cout
<< endl;

return 0;
}

  LSD基数排序

基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

#define R 256

#define digit(a, d) ( a >> 8*d )

static BYTE *aux;

void radix_sort(BYTE *arr, int left, int right)
{
if(left < right)
{
int d = 0;
for(d=3; d>=0; d--)
{
int i=0, j=0, count[R+1];
for(j=0; j<R; j++)
count[j]
= 0;
for(i=left; i<=right; i++)
count[digit(arr[i],d)
+ 1]++;
for(j=1; j<R; j++)
count[j]
+= count[j-1];
for(i=left; i<=right; i++)
aux[count[digit(arr[i],d)]
++] = arr[i];
for(i=left; i<=right; i++)
arr[i]
= aux[i-1];
}
}
}

void RadixSort(BYTE *array,int length)
{
aux
= (BYTE*)malloc(length);
radix_sort(array,
0,length-1);
free(aux);
}

  对于int 的LSD基数排序

  

#include <stdio.h> 
#include
<stdlib.h>

void radixSort(int[]);

int main(void) {
int data[10] = {73, 22, 93, 43, 55, 14, 28, 65, 39, 81};

printf(
"\n排序前: ");
int i;
for(i = 0; i < 10; i++)
printf(
"%d ", data[i]);

putchar(
'\n');

radixSort(data);

printf(
"\n排序後: ");
for(i = 0; i < 10; i++)
printf(
"%d ", data[i]);

return 0;
}

void radixSort(int data[]) {
int temp[10][10] = {0};
int order[10] = {0};

int n = 1;
while(n <= 10) {

int i;
for(i = 0; i < 10; i++) {
int lsd = ((data[i] / n) % 10);
temp[lsd][order[lsd]]
= data[i];
order[lsd]
++;
}

// 重新排列
int k = 0;
for(i = 0; i < 10; i++) {
if(order[i] != 0) {
int j;
for(j = 0; j < order[i]; j++, k++) {
data[k]
= temp[i][j];
}
}
order[i]
= 0;
}

n
*= 10;
}
}

  

8 shell排序

#include <iostream>
using namespace std;

int sortGroup(int a[],int n,int begin,int step)
{
for(int i = begin + step;i < n; i += step)
{
for(int j = begin; j < i;j += step)
{
if(a[i] < a[j])
{
int tmp = a[i];
for(int k = i; k >j;k -= step)
{
a[k]
= a[k-step];
}
a[j]
= tmp;
}
}
}
return 1;
}
int shellSort(int a[],int n)
{
//以i进行分组,i每次循环之后减小为原来的一半
for(int i = n / 2; i > 0;i --)
//对每一个组进行排序
for(int j = 0;j < i;j ++)
sortGroup(a,n,j,i);
}
int main()
{
int a[10] = {4,10,9,8,7,6,5,4,3,2}; //创建10个数据,测试
shellSort(a, 10); //调用希尔排序
for(int i = 0;i < 10;i ++)
cout
<< a[i] << " ";
cout
<< endl;
return 0;
}

  9 桶排序

    桶排序的基本思想

   假设有一组长度为N的待排关键字序列K[1....n]。首先将这个序列划分成M个的子区间(桶) 。然后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着对每个桶B[i]中的所有元素进行比较排序(可以使用快排)。然后依次枚举输出B[0]....B[M]中的全部内容即是一个有序序列。

[桶—关键字]映射函数

      bindex=f(key)   其中,bindex 为桶数组B的下标(即第bindex个桶), k为待排序列的关键字。桶排序之所以能够高效,其关键在于这个映射函数,它必须做到:如果关键字k1<k2,那么f(k1)<=f(k2)。也就是说B(i)中的最小数据都要大于B(i+1)中最大数据。很显然,映射函数的确定与数据本身的特点有很大的关系,我们下面举个例子:

假如待排序列K= {49、 38 、 35、 97 、 76、 73 、 27、 49 }。这些数据全部在1—100之间。因此我们定制10个桶,然后确定映射函数f(k)=k/10。则第一个关键字49将定位到第4个桶中(49/10=4)。依次将所有关键字全部堆入桶中,并在每个非空的桶中进行快速排序

    

#include<iostream>
#include
<malloc.h>
using namespace::std;

typedef
struct node{
int key;
struct node * next;
}KeyNode;

void inc_sort(int keys[],int size,int bucket_size){
KeyNode
**bucket_table=(KeyNode **)malloc(bucket_size*sizeof(KeyNode *));
for(int i=0;i<bucket_size;i++){
bucket_table[i]
=(KeyNode *)malloc(sizeof(KeyNode));
bucket_table[i]
->key=0; //记录当前桶中的数据量
bucket_table[i]->next=NULL;
}
for(int j=0;j<size;j++){
KeyNode
*node=(KeyNode *)malloc(sizeof(KeyNode));
node
->key=keys[j];
node
->next=NULL;
//映射函数计算桶号
int index=keys[j]/10;
//初始化P成为桶中数据链表的头指针
KeyNode *p=bucket_table[index];
//该桶中还没有数据
if(p->key==0){
bucket_table[index]
->next=node;
(bucket_table[index]
->key)++;
}
else{
//链表结构的插入排序
while(p->next!=NULL&&p->next->key<=node->key)
p
=p->next;
node
->next=p->next;
p
->next=node;
(bucket_table[index]
->key)++;
}
}
//打印结果
for(int b=0;b<bucket_size;b++)
for(KeyNode *k=bucket_table[b]->next; k!=NULL; k=k->next)
cout
<<k->key<<" ";
cout
<<endl;
}

int main(){
int raw[]={49,38,65,97,76,13,27,49};
int size=sizeof(raw)/sizeof(int);
inc_sort(raw,size,
10);
return 0;
}

  

   10  鸽巢排序,先统计重复的数据,再排序,减少 比较次数。数度是stl::sort20多倍,stl中的sort采用的是模板化

     的快排的。

    缺点是需要一个size至少等于待排序数组取值范围的缓冲区,不适合int等大范围数据,但是如果内存狗用的话,也可以对int 型的数据进行排序

void PigeonholeSort(BYTE *array, int length)
{
int b[256] = {0};
int i,k,j = 0;
for(i=0; i<length; i++)
b[array[i]]
++;
for(i=0; i<256; i++)
for(k=0; k<b[i]; k++)
array[j
++] = i;
}

  对int型的进行排序,有一个问题是下面的程序只能对最大为256 的进行排序

#include <iostream>
using namespace std;
void pigeonholeSort(int a[],int n)
{
int j = 0;
int b[256] = {0};
for(int i = 0;i < n;i ++)
b[a[i]]
++;

for(int i = 0;i < 256; i ++)
for(int k = 0;k < b[i]; k ++)
a[j
++] = i;
}
int main()
{
int a[10] = {3,4,9,8,5,6,7,2,1,0};
pigeonholeSort(a,
10);

for(int i = 0;i < 10;i ++)
cout
<< a[i] << " ";
cout
<< endl;

return 0;
}

  改进一下:不限制数的大小,根据输入数据的最大值来确定边界

#include <iostream>
using namespace std;
void pigeonholeSort(int a[],int n)
{
int j = 0;
int b[256] = {0};
for(int i = 0;i < n;i ++)
b[a[i]]
++;

for(int i = 0;i < 256; i ++)
for(int k = 0;k < b[i]; k ++)
a[j
++] = i;
}
void pigeonholesort2(int a[],int n,int maxValue)
{
int j = 0;
//int b[maxValue] = {0};
int b[maxValue];

for(int i = 0; i < maxValue; i ++)
b[i]
= 0;
for(int i = 0;i < n;i ++)
b[a[i]]
++;
for(int i = 0;i < maxValue; i ++)
for(int k = 0; k < b[i]; k ++)
a[j
++] = i;
}
int main()
{
int a[10] = {3,4,9,8,5,6,7,2,1,10};
pigeonholeSort(a,
10);

for(int i = 0;i < 10;i ++)
cout
<< a[i] << " ";
cout
<< endl;

cout
<< "------------------------------" << endl;
int b[10] = {3,4,9,8,5,6,7,2,1,10};
int max = 0;
for(int i = 0;i < 10;i ++)
if(max < b[i])
max
= b[i];

cout
<< "max value :" << max << endl;
pigeonholesort2(b,
10,max);
for(int i = 0;i < 10;i ++)
cout
<< b[i] << " ";
cout
<< endl;
return 0;
}

  

  改进版的鸽巢排序,先找出最大、最小值,减少比较次数。

   排序字节串的话速度约是鸽巢排序的一半,多一次遍历的计数排序

 

void CountingSort(BYTE *array, int length)
{
int t;
int i, z = 0;
BYTE min,max;
int *count;
min
= max = array[0];
//先求最大最小值
for(i=0; i<length; i++)
{
if(array[i] < min)
min
= array[i];
else if(array[i] > max)
max
= array[i];
}
count
= (int*)malloc((max-min+1)*sizeof(int));
for(i=0; i<max-min+1; i++)
count[i]
= 0;
for(i = 0; i < length; i++)
count[array[i]
-min]++;
// 上面的鸽巢排序
for(t = 0; t <= 255; t++)
for(i = 0; i < count[t-min]; i++)
array[z
++] = (BYTE)t;
free(count);
}

  另外的排序算法还有

   Burstsort,球排序等,明天继续

http://en.wikipedia.org/wiki/Burstsort 

  http://zh.wikipedia.org/wiki/Bead_sort

维基百科真强 啊 !

参考:

http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/RadixSort.htm

http://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F

http://apps.hi.baidu.com/share/detail/18982727

posted @ 2011-08-22 21:51  wtx  阅读(662)  评论(0编辑  收藏  举报