归并排序

来源:互联网 发布:经典的c语言源代码网站 编辑:程序博客网 时间:2024/06/11 18:36

归并排序也是分治策略的一种应用,基本思想是:一个已经排序好的数组可以由他的两个已经排序好的子数组得到(依次从两个子数组中拿出较小(或较大,取决于排序方式)的元素放回到父数组中,如果一个数组中的元素已经全部拿刀父数组中去了,就把剩下的元素全部放回到父数组的后面);而排序好的子数组当然也可以用同样的方式得到,也就是说要将待排序的数组不断划分,直到划分成的子数组中只有一个元素为止。

#include<stdio.h>#include<stdlib.h>#define random(n) (rand()%n)#define N12#define NOTATION 99999999//这个做法在每个子数组的后面设置了哨兵,当有效的数组全部被复制会父数组的之后,//达到了这个哨兵,由于这个哨兵是一个非常大的数字,所以在与另外一个没有复制完成的//数组进行比较的时候,每次都是将没有复制完成的数组中的元素复制会父数组//这种做法的优点是不需要每复制一次就判断子数组有没有复制完成/*void merge(int *a,int p,int q,int r){int n1=q-p+1;int n2=r-q;int *L=(int *)malloc(sizeof(int)*n1);int *R=(int *)malloc(sizeof(int)*n2);int i,j,k;for(i=0;i<n1;i++){L[i++]=a[p+i];i--;}for(j=0;j<n2;j++){R[j++]=a[q+j+1];j--;}L[n1]=NOTATION;//设置哨兵R[n2]=NOTATION;i=0;j=0;for(k=p;k<=r;k++){if(L[i]<=R[j]){a[k]=L[i];i++;}else{a[k]=R[j];j++;}}}*///这个做法没有设置哨兵,但是需要在每次复制完成之后判断两个子数组是否已经复制完成,//如果有一个子数组已经复制完成,那么将另外的一个子数组中的元素全部复制到父数组中void merge(int *a,int p,int q,int r){int n1=q-p+1;int n2=r-q;int *L=(int *)malloc(sizeof(int)*n1);int *R=(int *)malloc(sizeof(int)*n2);int i,j,k;for(i = 0;i < n1; i++){L[i++] = a[p+i];i--;}for(j = 0;j < n2; j++){R[j++] = a[q+j+1];j--;}i=0;j=0;for(k = p; k <= r; k++){if(L[i] <= R[j]){a[k]=L[i];i++;}else{a[k] = R[j];j++;}if(i >= n1){  //L已经复制完了for(k++; j < n2; j++, k++)a[k] = R[j];break;}else if(j >= n2) { //R已经复制完了for(k++; i < n1; i++, k++)a[k] = L[i];break;}}}void merge_sort(int *A,int p,int r){int q;if(p < r){q=(p+r)/2;merge_sort(A, p, q);merge_sort(A, q+1, r);merge(A, p, q, r);}}void main(){int n=0;int i=0;int j=0;int a[N];printf("排序前:\n");for(n = 0; n < N; n++){a[n] = random(100);printf("%-5d", a[n]);}printf("\n");merge_sort(a, 0, N);printf("排序后:\n");for(i=1; i <= N; i++)printf("%-5d", a[i]);printf("\n");}

代码中的merge方法用于将两个已经排序好的子数组合并成一个排序好的数组,上面提供了两种方式,两种方式的区别在注释中有说明。

复杂度分析:

当问题规模为n时,代码中将每个问题都划分为两个规模为n/2的子问题,将问题分解需要的时间为C(n),将问题合并需要的时间为D(n),所以T(n) = 2*T(n/2) + C(n) + D(n),也即T(n) = Ɵ(nlgn)。

0 0
原创粉丝点击