本文内容来自大牛Robert Sedgewick写的《Algorithms in C》一书和Coursera上的大牛讲的算法课。
一.选择排序(Selection Sort)
1.工作过程:首先,选出数组中最小的元素,将它与数组中第一个元素交换。然后,再选出余下数组元素最小的,将它与数组中第二个元素交换,以此类推,直到最后数组中剩余最后一个未排序的元素,即完成。如图1所示:
图1.选择排序
2.CODE:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 typedef int Item; 5 #define key(A) (A) 6 #define less(A,B) (key(A)<key(B)) 7 #define exch(A,B) {Item t=A;A=B;B=t;} 8 #define compexch(A,B) if(less(B,A)) exch(A,B) 9 void selection(char s[],int l,int r)//l为数组第一个元素,r为数组最后一个元素 10 { 11 int i,j; 12 for(i=l;i<r;i++) 13 { 14 int min=i;//min保存最小的数组元素下标 15 for(j=i;j<=r;j++) 16 if(less(s[j],s[min]))min=j; 17 exch(s[i],s[min]);//将最小元素交换到最终位置上 18 } 19 } 20 int main(void) 21 { 22 char s[]="asortingexample"; 23 printf("%s ",s); 24 selection(s,0,strlen(s)-1); 25 printf("%s ",s); 26 return 0; 27 }
3.缺点:对有序的文件和无序的文件排序时间基本相同。
二.插入排序(Insertion Sort)
1.工作过程:在排序过程中当前索引左边的元素都是排好序的,不过它们不是处于最终的位置上,因为之后他们还需要向右移动来为更小的元素腾出空间。当索引移动到最右边时,即完成排序。如图所示:
图2.插入排序
2.CODE:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 typedef int Item; 5 #define key(A) (A) 6 #define less(A,B) (key(A)<key(B)) 7 #define exch(A,B) {Item t=A;A=B;B=t;} 8 #define compexch(A,B) if(less(B,A)) exch(A,B) 9 void insertion(char s[],int l,int r) 10 { 11 int i,j; 12 for(i=r;i>l;i--)//首先遍历一遍数组,找出最小元素,交换到第一位当作观察哨。 13 compexch(s[i-1],s[i]); 14 for(i=l+2;i<=r;i++)//然后从第三个元素开始插入排序(前两个元素已经有序)。 15 { 16 char v; 17 j=i; 18 v=s[i]; 19 while(less(v,s[j-1]))//为待插入的元素找到合适的插入点,索引左边的有序元素依次右移。 20 { 21 s[j]=s[j-1]; 22 j--; 23 } 24 s[j]=v; 25 } 26 27 } 28 int main(void) 29 { 30 char s[]="asortingexample"; 31 printf("%s ",s); 32 insertion(s,0,strlen(s)-1); 33 printf("%s ",s); 34 return 0; 35 }
3.特点:插入排序的运行时间和带排序的文件数据的原始排列顺序密切相关,在已经排好序的文件数据中排序,插入比选择快。
三.冒泡排序(Bubble Sort)
1.工作过程:两两比较相邻记录的元素,当遇到最小的元素时,将它与左边的元素逐个交换,直到将最小的元素移动到队列的最左端,以此类推。冒泡排序实际上是一种选择排序,但需要更多工作将每个元素放到合适的位置。在所有的比较操作中,最小的元素像是泡泡那样“冒”到最前端。如图3:
图3.冒泡排序
2.CODE:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 typedef int Item; 5 #define key(A) (A) 6 #define less(A,B) (key(A)<key(B)) 7 #define exch(A,B) {Item t=A;A=B;B=t;} 8 #define compexch(A,B) if(less(B,A)) exch(A,B) 9 void bubblesort(char s[],int l,int r) 10 { 11 int i,j,b=1; 12 for(i=l;i<r&&b;i++) 13 { 14 b=0;//标志位,如果内部循环没有进行任何交换操作,即文件已经排好序,可以终止外部循环。 15 for(j=r;j>i;j--) 16 if(less(s[j],s[j-1]))//相邻两元素两两比较 17 { 18 exch(s[j],s[j-1]); 19 b=1; 20 } 21 } 22 } 23 int main(void) 24 { 25 char s[]="asortingexample"; 26 printf("%s ",s); 27 bubblesort(s,0,strlen(s)-1); 28 printf("%s ",s); 29 return 0; 30 }
3.特点:容易实现,不过其执行速度比另外选择和插入排序方法慢。
四.希尔排序(ShellSort)
1.工作过程:插入排序运行效率低的原因是因为它所执行的交换操作涉及近邻的元素,使得元素每次只能移动一位。希尔排序是插入排序的扩展,它通过允许非相邻的元素进行交换来提高执行效率。在使文件变成有序的时候,通过将较大的元素右移,把h子文件中某些元素的前面。使用插入排序来完成这项工作,只是将移动的增量由1变为了h。h序列:3*h+1:1,4,13,40,121...。如图4所示:
图4.希尔排序
2.CODE:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 typedef int Item; 5 #define key(A) (A) 6 #define less(A,B) (key(A)<key(B)) 7 #define exch(A,B) {Item t=A;A=B;B=t;} 8 #define compexch(A,B) if(less(B,A)) exch(A,B) 9 void shellsort(char s[],int l,int r) 10 { 11 int i,j,h; 12 for(h=1;h<(r-l);h=h*3+1)//h序列,希尔排序适合大数据,可以写成h<=(r-l)/9; 13 ; 14 do{ 15 for(i=l+h;i<=r;i++) 16 { 17 j=i;char v=s[i]; 18 while(j>=l+h && less(v,s[j-h]))//增量为h的插入排序 19 { 20 s[j]=s[j-h]; 21 j-=h; 22 } 23 s[j]=v; 24 } 25 h/=3; 26 }while(h>0); 27 } 28 int main(void) 29 { 30 char s[]="asortingexample"; 31 printf("%s ",s); 32 shellsort(s,0,strlen(s)-1); 33 printf("%s ",s); 34 return 0; 35 }
3.特点:即使对于大文件,希尔排序算法都具有较高的运行效率以及代码简单易行,很多排序陈旭都选择了希尔排序。
五.稳定
定义:如果排序后文件中具有相同关键字的元素的相对位置保持不变,称一个排序方法是稳定的。