排序算法小结

Posted fugeny

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法小结相关的知识,希望对你有一定的参考价值。

sort对象

  • sort对象需要实现了comparable接口,comparable中包含compareTo()方法
  • 内置comparable的对象有:Integer,Double,String,Date,File...
  • compareTo()方法中,less返回-1,equal返回0,more返回+1

选择排序(selection sort)

  1. 游标从左向右移动
  2. 每次移动前检索游标右方所有元素的最小值,将其与游标位置元素互换
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;
        exchange(a, i, min);
    }
}

用时:(N^2/2)的compare与N的置换操作,对于任意情况都是如此,运行较慢

插入排序(insertion sort)

  1. 将游标 i 位置的元素与其左边的元素比较,如果游标元素小,则置换
public static void sort(Comparable[] a){
    int N = a.length;
    for (int i = 0; i < N; i++)
        for (int j = i; j > 0; j--)
            if (less(a[j], a[j-1]))
                exch(a, j, j-1);
            else break;
}

用时:

  • 对于随机数组,(N^2/4)的compare与(N^2/4)的交换
  • 对于升序(ascending)的数组,N-1次compare,0次交换
  • 对于降序(descending)的数组,(N^2/2)的compare与(N^2/2)的交换
  • 对于部分排序的数组,用时为cN

希尔排序(shellsort)

将数组A[N]变化成一个矩阵B[w][],即按w将A[N]中的元素从左至右,从上至下依次填入矩阵B中,然后对B中的每一列进行排序,通常采用插入排序。
对于w会采用一个增量序列,例如{1,4,13,40,121,364...3w[i-1]+1},先选取小于N的最大w,然后排序,再往下选择新的w进行计算,直至w=1
3x+1序列的用时为(O(N^{3/2}))

归并排序(mergesort)

采用分而治之的思想,基本思路如下:

  1. 将序列均分为两部分
  2. 迭代排序每部分
  3. 合并两部分
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi){
    if (hi <= lo) return;
    int mid = lo + (hi - lo) / 2;
    sort(a, aux, lo, mid);
    sort(a, aux, mid+1, hi);
    merge(a, aux, lo, mid, hi);
}

用时:(O(N*lgN))
实际使用更改:

  • 对于长度较小的序列(如7个以下),采用插入排序
  • 如果两个部分已经区分大小a[mid] < a[mid+1],则直接连接,而非merge

快速排序(quicksort)

  1. 重置数组(保证效率)
  2. 分组:选择a[j],将小于a[j]的元素放到其左边,大于a[j]的元素放到右边
  3. 对左右部分递归分组
public class Quick{
    private static int partition(Comparable[] a, int lo, int hi){ 
        int i = lo, j = hi+1;
        while (true)
        {
            while (less(a[++i], a[lo]))
                if (i == hi) break;
            while (less(a[lo], a[--j]))
                if (j == lo) break;
            if (i >= j) break;
            exch(a, i, j);
        }
        exch(a, lo, j);
        return j; 
    }

    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);
    }
}

用时:一般情况下快速排序比归并排序更快,但在不利情况下(选择最小或最大元素),快速排序用时为(O(N^2))
快速排序是不稳定排序,归并排序是稳定排序,java中对于Object采用归并排序,在注重效率时采用快速排序
快速排序在实际操作中采用如下方式加快速度:

  • 对分隔得小的序列采用插入排序
  • 通过样本来获取median元素

快速排序对于重复元素值是敏感的,当重复元素过多是上述排序过程近乎二次方的用时,而归并排序相对不敏感。
处理重复元素的方法是采用3分法(3-way partitioning),即选取元素a[j]后,将数组分为小于、等于、大于a[j]的3部分,3分法的用时大大缩小,比归并排序小许多

排序方法总结

- stable? worst average best remarks
selection - (N^2/2) (N^2/2) (N^2/2) N exchanges
insertion ? (N^2/2) (N^2/4) N use for small N or partially ordered
shell - ? ? N tight code, subquadratic
merge ? (N*lg(N)) (N*lg(N)) (N*lg(N)) guarantee, stable
quick - (N^2/2) (2N*ln(N)) (N*lg(N)) (N*lg(N)) probabilistic guarantee fastest in practice
3-way quick ? (N^2/2) (2N*ln(N)) N holy sorting grail

应用

数组重置shuffle

  1. 给数组每个元素分配对应的随机数,对随机数进行排序并交换数组元素,达到重置效果
  2. knuth shuffle,取得0到N的两个随机数i,j,交换A[i]与A[j]

选择selection
选择排第k的元素。
采用类快速排序的方式,随机选取元素进行分组,如果左边元素为k-1,则直接返回所选元素,如果左边元素小于k-1,则说明所选元素在右边,在右边继续重复选择;否则在左边重复选择过程。

public static Comparable select(Comparable[] a, int k){
    StdRandom.shuffle(a);
    int lo = 0, hi = a.length - 1;
    while (hi > lo){
        int j = partition(a, lo, hi);
        if (j < k) lo = j + 1;
        else if (j > k) hi = j - 1;
        else return a[k];
    }
    return a[k];
}

凸包(convex hull)
在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。
算法:

  • 选择X集合中y最小的点作为元点p
  • 对其它点按照到p的角坐标(alpha)进行排序
  • 按序号依次将点放入凸包S中,如果新点与前两点是逆时针关系,则将该点拿出S

    顺势正判别可以采用计算三角形面积的方式(向量法)

目前以有的排序算法有数百个,此处选择用得最多的几个
参考Princeton University Algorithm I












以上是关于排序算法小结的主要内容,如果未能解决你的问题,请参考以下文章

各种基本算法实现小结—— 排序算法

排序算法小结

常见排序算法小结

常见排序算法小结

常见排序算法小结

算法小结