第二章 排序(一) - 《算法》读书笔记

第二章 排序(一)

2.1 初级排序算法

2.1.1 游戏规则

  • 排序的目标:将所有元素的主键按照某种方式排列。
  • 排序类算法的模板:
public class Example{
    public static void sort(Comparable[] a){}//对实现comparable接口对象组成的数组排序
    public static boolean less(Comparale v, Comparable w){//v是否小于w
        return v.compareTo(w) < 0;
    }
    public static void exch(Comparable a, int i, int j){//交换索引为i和j的对象
        Comparable t = a[i]; a[i] = a[j]; a[j] = t;
    }
    public static void show(Comparable[] a){//在单行中打印数组
        for(int i = 0; i < a.length; i++)
            StdOut.print(a[i] + " ");
        StdOut.println();
    }
    public static boolean isSorted(Comparable[] a){//测试数组是否有序
        for(int i = 1; i < a.length; i++)
            if(less(a[i], a[i-1]))//排序后索引较大的主键大于等于索引较小的主键
                return false;
    }
}
  • 在创建自己的数据类型是,只需要实现Comparable接口,就可以保证可排序,需要实现compareTo()方法来定义目标类型对象的自然次序

2.1.2 选择排序

  • 不断选择剩余元素之中的最小者,与剩余元素中最前面的元素交换。
  • 算法如下:
public class Selection{
    public static void sort(Comparable[] a){//将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;
            exch(a, i, min);
        }
    }
}
  • 交换次数总是N,算法效率取决于比较次数
  • 比较次数大约为N2/2
  • 选择排序的特点:
    • 运行时间和输入无关
    • 移动数据是最少的

2.1.3 插入排序

  • 将元素一个一个插入到其他有序元素中,其余所有元素在插入前都要右移一位。
  • 算法如下:
public class Insertion{
    public static void sort(Comparable[] a){
        int N = a.length;
        for(int i = 1; i < N; i++)//将a[i]插入到a[i-1]、a[i-2]、a[i-3]...之中
            for(int j = i; j > 0 && less(a[j], a[j-1]); j--)
        		exch(a, j, j-1);//a[i]与a[0]到a[i-1]中所有比它小的元素依次有序交换
    }
}
  • 插入排序所需时间取决于输入中元素的初始顺序
  • 平均情况下需要N<sup>2</sup>/4次比较以及N2/4次交换;最坏情况下需要N<sup>2</sup>/2次比较以及N2/2次交换;最好情况下需要N-1次比较和0次交换。
  • 插入排序对于部分有序的数组十分高效
    • 部分有序:数组中倒置的数量小于数组大小的某个倍数

2.1.5 比较两种排序算法

  • 对于随机排序的无重复主键的数组,插入排序和选择排序的运行时间是平方级别的,两者之比应是一个较小的常数。

2.1.6 希尔排序

  • 希尔排序的思想是使数组中任意间隔为h的元素都是有序的。
  • 算法中将h按照递增序列递减,通过插入排序实现h有序数组
  • 对于任意以1结尾的h序列, 都能将数组排序。
  • 算法如下:
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;
    }
}
  • 希尔排序更高效的原因是它权衡了子数组的规模和有效性
    • 排序之前各个子数组很短
    • 排序之后子数组都是部分有序
posted @ 2021-01-23 22:33  一天到晚睡觉的鱼  阅读(110)  评论(0)    收藏  举报