排序的元素实现了Comparable接口,以达到对于通用性.
最基础的排序是冒泡排序,下面是其思路:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
-
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较.
下面是其实现代码:
public class Maopao { public void sort(Comparable[] a) { int N=a.length; for(int i=0;i<N;i++) { for(int j=0;j<N-i-1;j++) { if(less(a[j+1],a[j])) { exch(a,j+1,j); } } } } public static void exch(Comparable[] a, int i, int min) { Comparable t=a[i]; a[i]=a[min]; a[min]=t; } public static boolean less(Comparable v, Comparable w) { return v.compareTo(w)<0; } }
冒泡排序,在最好的情况下(即已经排好序的情况)需要N2/2比较,0次交换.在最坏的情况下(倒序的序列元素),需要N2/2次比较,N2/2次交换,效率很低.
选择排序的思路如下:
- 首先找到数组中最小的元素,其次将它和第一个元素交换位置.(如果第一个元素就是最小的元素,就与自己交换)
- 然后在剩下的元素中,找到最小的元素,将它与数组中的第二个元素交换位置.
- 如此往复,直到数组排好序.
代码如下:
public class Selection { public static void sort(Comparable[] a) { int N=a.length; for(int i=0;i<N;i++) { int min=i; for(int j=i+1;j<N;j++) { if(less(a[j],a[min])) min=j; //(N-1)+(N-2)+...+1次比较N*N/2次交换 } exch(a,i,min); //这里进行了交换,用到了N次交换 } } public static void exch(Comparable[] a, int i, int min) { Comparable t=a[i]; a[i]=a[min]; a[min]=t; } public static boolean less(Comparable v, Comparable w) { return v.compareTo(w)<0; } }
对于长度为N的数组,选择排序大约需要N2/2次比较和N次交换.选择排序有两个鲜明的特点:运行时间和输入无关:一个已经有序的数组和随机排列的数组同样大小所需要的时间一样长.数据移动是最少的:每次交换都会改变两个数组元素的值,因此选择排序用了N次交换.
插入排序的思路如下:
可以通过整理扑克来理解:一张一张的来,将每一张牌,插入到其他已经有序的牌中的适当的位置
- 从数组的第二个元素开始,将其插入到前面的元素中
- 如果当前元素比前一个元素小,那么将两个元素交换位置,否则,停止循环,此时索引前面的元素均以排好序
- 如此往复直到数组排好序.当索引到达数组的右端的时候,排序就已经完成了.
下面是代码:
public class Insertion { public static void sort(Comparable[] a) { int N=a.length; for(int i=1;i<N;i++) { for(int j=i;j>0&&less(a[j],a[j-1]);j--) { exch(a,j,j-1); } } } public static void exch(Comparable[] a, int i, int min) { Comparable t=a[i]; a[i]=a[min]; a[min]=t; } public static boolean less(Comparable v, Comparable w) { return v.compareTo(w)<0; } }
最好的情况:(数组已经有序了):交换0次, N-1次比较,最坏的情况:(数组倒序排列):交换:~N2/2;比较和交换的次数相同.插入排序平均需要~N2/4次比较以及~N2/4次交换.
希尔排序是一种基于插入排序的算法,希尔排序的思路是交换不相邻的元素以及对于数组局部进行排序,并且最终用插入排序将局部有序的数组排序.
希尔排序使数组中任意间隔为k的元素都是有序的,实现希尔排序需要对于每个h,用插入排序将h个子数组独立的排序,然后将h按照一定比例减小直到为1.希尔排序权衡了子数组的规模和有序性,排序之初,每个子数组都很短,排序之后子数组部分有序,这两种情况都很适合插入排序.希尔排序的代码如下:
public class Shell { public static void sort(Comparable[] a) { int N=a.length; int k=1; while(k<N/3) k=3*k+1; while(k>=1) { for(int i=k;i<N;i++) { for(int j=i;j>=k&&less(a[j],a[j-k]);j-=k) { exch(a,j,j-k); } } k=k/3; //不断减小k,当k为1的时候,就是插入排序 } } public static void exch(Comparable[] a, int i, int min) { Comparable t=a[i]; a[i]=a[min]; a[min]=t; } public static boolean less(Comparable v, Comparable w) { return v.compareTo(w)<0; } }