学习算法的第一天-------初级排序算法

所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。

排序算法类模板

——————————————————————————————————————————

public class Example{
    public static void sort(Comparable[] a){
    }
    private static boolean (lessComparable 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[] = t;
    }
    private static void show (Comparable[] a){
        //在单行中打印数组
        for(int i = 0; i < a.length; i++)
            StdOut.print(a[i] + " ");
        StdOut.printIn();
    }
    public static boolean isSorted(Comparable[] a){
        //测试数组元素是否有序
        for(int i = 1; i < a.length; i++_)
        if(less(a[i], a[i - 1])) return false;
        return true;
    }
    public static void main(String[] args){
        //从标准输入读取字符串,将它们排序输出
        String[] a = In.readStrings();
        sort(a);
        assert isSorted(a);
        show(a);
    }
}

——————————————————————————————————————————

选择排序

  一种最简单的排序算法是这样的:首先,找到数组中小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。这种方法叫做选择排序,因为它在不断地选择剩余元素之中的最小者。

  总的来说,选择排序是一种很容易理解和实现的简单排序算法,它有两个很鲜明的特点。

  运行时间和输入无关。为了找出最小的元素而扫描一遍数组并不能为下一遍扫描提供什么信息在计算机的实现中这种性质在某些情况下是缺点,因为使用选择排序的人可能会惊讶地发现,一个已经有序的数组或动一位。这种算法与选择排序一是主键全部相等的数组和一个元素随机排列的数组所用的排序时间竟然一样长!我们将会看到,其他算法会更善于利用输入的初始状态。

  数据移动是最少的。每次交换都会改变两个数组元素的值,因此选择排序用了N次交换交和选择排序不换次数和数组的大小是线性关系。我们将研究的其他任何算法都不具备这个特征(大部分的增长数且其中的元素已量级都是线性对数或是平方级别)。

选择排序代码

——————————————————————————————————————————

 1 public class Selection{
 2   pubic static void sort(Comparable[]){
 3         //将a[]按升序排列
 4         int N = a.length;        //数组长度
 5         for(int i = 0; i < N; i++){
 6             //将a[i]到a[i+1..N]中的最小元素交换
 7             int min = i;         //最小元素的索引
 8             for(int j = i + 1; j < N; j++)
 9                 if(less(a[j],a[min])) min=j;
10             exch(a, i, min);
11         }
12     }
13 }
14 //less(),exch(),isSorted()和main()等方法见“排序算法类模板”

——————————————————————————————————————————

插入排序

  通常人们整理桥牌的方法是一张一张的来,将每一张牌插入到其他已经有序的牌中的适当位置。在计算机的实现中,为了给要插入的元素腾出空间我们需要将其余所有元素在插入之前都向右移动一位。这种算法叫做插入排序。

  与选择排序一样,当前索引左边的所有元素都是有序的,但它们的最终位置还不确定,为了给更小的元素腾出空间,它们可能会被移动。但是当索引到达数组的右端时,数组排序就完成了。

  和选择排序不同的是,插入排序所需的时间取决于输入中元素的初始顺序。例如,对一个很大且其中的元素已经有序(或接近有序)的数组进行排序将会比对随机顺序的数组或是逆序数组进行排序要快得多。

插入排序代码

——————————————————————————————————————————

public class Insertion{
    pubic static void sort(Comparable[]){
        //将a[]按升序排列
        int N = a.length;        //数组长度
        for(int i = 1; i < N; i++){
            //将a[i]插入到a[i-1]..之中
            for(int j = i; j > 0 && less(a[j],a[j-1]); j--)
                exch(a, j, j-1);
        }
    }
}
//less(),exch(),isSorted()和main()等方法见“排序算法类模板”

——————————————————————————————————————————

希尔排序

  为了展示初级排序算法性质的价值,接下来我们将学习一种基于插入排序的快速的排序算法对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端。例如,如果主键最小的元素正好在数组的尽头,要将它挪到正确的位置就需要N-1次移动。希尔排序为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

  希尔排序的思想是使数组中任意间隔为h的元素都是有序的这样的数组被称为h有序数组换句话说,一个h有序数组就是h个互相独立的有序数组编织在一起组成的一个数组(见图2.12)在进行排序时,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序创造方便用这种方式,对于任意以1结尾的h序列,我们都能够将数组排序。这就是希尔排序。算法23的实现使用了序列1/2(32-1),从N3开始递减至1。我们把这个序列称为递增序列。算法23实时计算了它的递增序列,另一种方式是将递增序列存储在一个数组中。

 h=4

  L  E  E  A  M  H  L  E  P  S  O  L  T  S  X  R

  L  ——————  M  ——————  P  ——————  T

     E  ———————  H  ——————  S  ——————  S

       E  ———————  L  ——————  O  ——————  X

           A  ———————  E  ———————  L  —————  R

           一个h有序数组即一个由h个有序子数组组成的数组
  实现希尔排序的一种方法是对于每个h,用插入排序将h个子数组独立地排序。但因为子数组是相互独立的,一个更简单的方法是在h-子数组中将每个元素交换到比它大的元素之前去(将比它大的元素向右移动一格)。只需要在插入排序的代码中将移动元素的距离由1改为h即可。这样希尔排序的实现就转化为了一个类似于插入排序但使用不同增量的过程。
希尔排序更高效的原因是它权衡了子数组的规模和有序性。排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。子数组部分有序的程度取决于递增序列的选择。透彻理解希尔排序的性能至今仍然是一项挑战。实际上,算法2.3是我们唯一无法准确描述其对于乱序的数组的性能特征的排序方法。

希尔排序代码

——————————————————————————————————————————

public class Shell{
    public static void sort(Comparable[] a){
        //将a[]按升序排列
        int N = a.length;
        int h = 1;
        while(h < n/3) h = 3h + 1;    //1,4,13,40,121,364,1093...
        while(h >= 1){
            //将数组变为h有序
            for(int i = h; i < N; i++){
            //将a[i]插入到a[i - h],a[i - 2h],a[i - 3*h]...之中
                for(int j = i; j >= h && less(a[j], a[j - h]); j -= h)
                    exch(a, j, j - h);
            }
                h = h/3;
        }
    }
}
//less(),exeh(), isSorted()和main()等方法见“排序算法类模"

——————————————————————————————————————————

猜你喜欢

转载自www.cnblogs.com/algorithms-learn-note/p/10974601.html