即使你只是使用标准库中的排序函数,学习排序算法仍然有三大实际意义:
- 对排序算法的分析将有助于你全面理解本书中比较算法性能的方法;
- 类似的技术也许能有效解决其他类型的问题;
- 排序算法常常是我们解决其他问题的第一步。
选择排序
一种最简单的排序算法是这样实现的:首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素,那么它就和自己交换)。再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。这种方法叫做选择排序,因为它在不断地选择剩余元素之中的最小值。
public class Selection{
public static void boolean less(Comparable v,Comparable w){
return v.compareTo(w)<0;
}
private static void exch(Comparable[] a,int i,int j){
Comparable t = a[i];a[i]=a[j];a[j]=t;
}
public static void sort(Comparable[] a){
int N = a.length;
for(int i=0;i<N;i++){
int min = i;
for(int j=i+i;j<N;j++){
if(less(a[j],a[min])) min = j;
exch(a,i,min);
}
}
}
插入排序
在计算机实现中,为了给要插入的元素腾出空间,我们需要将其余所有元素在插入之前都向后移动一位。这种算法叫做插入排序。
public class Insertion{
public static void sort(Comparable[] a){
int N = a.length;
for(int i=0;i<N;i++){
for(int j=i;j>0 && less(a[j],a[j-1]);j--) exch(a,j,j-1);
}
}
}
希尔排序
public class Shell{
public static void sort(Comparable[] a){
int N = a.length;
int h = 1;
while(h < N/3) h = 3*h + 1;
while(h >= 1){
for(int i = h; i < N; i++){
for(int j = i; j >= h && less(a[j],a[j-h]);j -= h) exch(a,j,j-h);
}
h = h/3;
}
}
}
归并排序
将两个有序的数组归并成一个更大的有序数组。要将一个数组排序,可以先(递归地)将它分成两半分别排序,然后将结果归并起来。归并排序最吸引人的性质是它能够保证将任意长度为N的数组排序所需时间和NlogN成正比;它的主要缺点是它所需的额外空间和N成正比。
这个博文讲的很明白:https://blog.csdn.net/collonn/article/details/17581953
快速排序
将一个数组分成两个子数组,将两部分独立地排序。快速排序和归并排序是互补的:归并排序将数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序;而快速排序将数组排序的方式则是当两个子数组都有序时整个数组也就自然有序了。在这一种情况中,递归调用发生在处理整个数组之前;在第二种情况中,递归调用发生在处理整个数组之后。在归并排序中,一个数组被等分为两半;在快速排序中,切分(partition)的位置取决于数组的内容。
public class Quick{
public static void sort(Comparable[] a){
StdRandom.shuffle(a);
sort(a,0,a.length-1);
}
private static void sort(Comparable[] a,int lo,int hi){
if(hi <= lo) return;
int j = partition(a,lo,hi);
sort(a,lo,j-1);
sort(a,j+1,hi);
}
}