算法导论1:插入排序和归并排序 2016.1.1
最近一段时间的博客都是记录我读《算法导论》的文字,虽然很厚,但是一点一点来吧,总有一天会看完的。虽然只看了几页,感觉收获还挺多的,原来懂了算法,却不一定能做出最好的代码(姿势很重要啊Orz。。),果然要跟着导论学习正确的姿势。
2016.1.1 今天看了两个算法:插入排序和归并排序。代码如下(C语言)
插入排序
1 #include<stdio.h> 2 3 void insertsort(int *a,int n) //默认存储到a[1..n]中 4 { 5 int i,j; 6 j=2; 7 for (j=2;j<=n;j++) { 8 i=j-1; 9 int key=a[j]; 10 while (i>0 && a[i]>key) { 11 a[i+1]=a[i]; 12 i--; 13 } 14 a[i+1]=key; 15 } 16 } 17 18 int main() 19 { 20 int n; 21 int a[11]={}; 22 scanf("%d",&n); 23 int i; 24 for (i=1;i<=n;i++) { 25 scanf("%d",&a[i]); 26 } 27 insertsort(a,n); 28 for (i=1;i<=n;i++) { 29 printf("%d |",a[i]); 30 } 31 return 0; 32 }
归并排序:
#include<stdio.h> void merge(int *a,int *b,int l,int mid,int r) { int i=l; int j=mid+1; int cou=l; while (i<=mid && j<=r) { if (a[i]<a[j]) { b[cou]=a[i]; i++; cou++; } else { b[cou]=a[j]; j++; cou++; } } while (i<=mid) { b[cou]=a[i]; i++; cou++; } while (j<=r) { b[cou]=a[j]; j++; cou++; } for (i=l;i<=r;i++) { a[i]=b[i]; } } void mergesort(int *a,int *b,int l,int r) { if (l<r) { int mid=(l+r)/2; mergesort(a,b,l,mid); mergesort(a,b,mid+1,r); merge(a,b,l,mid,r); } } int main() { int a[11]={},b[11]={}; int n,i; scanf("%d",&n); for (i=0;i<n;i++) { scanf("%d",&a[i]); } mergesort(a,b,0,n-1); for (i=0;i<n;i++) { printf("%d |",a[i]); } return 0; }
书中是通过这两个算法引出算法复杂度分析的思路,前者是一个n方的复杂度,后者是一个nlgn的复杂度。
另外,练习题中有一个很具有思考价值的问题,就是在归并排序中对小数组采用插入排序。
下面是引述书中的内容:
“插入排序的最坏情况运行时间为Θ(n^2),但插入排序中的常数因子可能使得它在n较小时,在许多机器上实际运行得要更快。 因此,在归并排序中当子问题变得足够小时,采用插入排序来使递归的叶变粗是有意义的。考虑对归并排序的一种修改。”
那么,在递归树的哪一层开始采用插入排序呢?这是一个值得思考的问题。
如果想看参考答案,可以看这里。http://clrs.skanev.com/02/problems/01.html
下面是对上面两个算法综合之后的排序算法,代码:
#include<stdio.h> #include<stdlib.h> #include<time.h> void merge(int *a,int *b,int l,int mid,int r) { int i=l; int j=mid+1; int cou=l; while (i<=mid && j<=r) { if (a[i]<a[j]) { b[cou]=a[i]; i++; cou++; } else { b[cou]=a[j]; j++; cou++; } } while (i<=mid) { b[cou]=a[i]; i++; cou++; } while (j<=r) { b[cou]=a[j]; j++; cou++; } for (i=l;i<=r;i++) { a[i]=b[i]; } } void insertsort(int *a,int l,int r) { int i,j; for (j=l+1;j<=r;j++) { i=j-1; int key=a[j]; while (i>l-1 && a[i]>key) { a[i+1]=a[i]; i--; } a[i+1]=key; } } void mixedmergesort(int *a,int *b,int l,int r) { if (l>=r) return ; if (r-l<20) insertsort(a,l,r); else { int mid=(l+r)/2; mixedmergesort(a,b,l,mid); mixedmergesort(a,b,mid+1,r); merge(a,b,l,mid,r); } } int main() { int a[101]={},b[101]={}; int n,i; scanf("%d",&n); srand(time(0)); for (i=1;i<=n;i++) { a[i]=rand()%100+1; } mixedmergesort(a,b,1,n); for (i=1;i<=n;i++) { printf("%d |",a[i]); } return 0; }