十大排序算法——选择排序&插入排序&希尔排序

时间复杂度(运行时间):比较数量+交换数量(不交换元素的算法则计算访问数组的次数)

空间复杂度(额外内存使用)


1. 选择排序

“不断地选择剩余元素之中的最小者”:找到数组中最小的元素,将它和数组第一个元素交换位置。然后在剩下元素中找到最小的元素,将它与数组第二个元素交换位置。如此往复,直到将整个数组排序。 

  • 交换的总次数是N,算法的时间效率取决于比较的次数
  • 选择排序需要大约N^2/2次比较(1+2+...+n-2+n-1)和N次交换

特点:

  • 运行时间和输入无关

  • 数据移动最少:交换次数和数组大小N是线性关系

//String、Integer已经实现了Comparable接口,自己就可以完成比较大小操作
public static void sort(Comparable[] a){
    //将a[]按升序排列
    int N = a.length;
    for (int i=0; i<N; i++){
        //将a[i]与a[i+1...N]中最小元素交换
        int min = i;//最小元素的索引
        for (int j=i+1; j<N; j++)
            if (a[j].compareTo(a[min])<0) min=j;
        //交换i和最小元素
        Comparable t = a[i];
        a[i] = a[min];
        a[min] = t;
    }
}

2. 插入排序

“类似于扑克牌”:当前索引左边的所有元素都是有序的,但他们的最终位置还不确定,为了给更小的元素腾出空间,它们可能会被移动。担当索引达到数组的右端时,数组排序就完成了。

  • 插入排序对部分有序数组很有效

  • 算法的时间效率取决于输入中元素的初始顺序

  • 情况比较次数交换次数
    平均情况N^2/4N^2/4
    最坏情况N^2/2N^2/2
    最好情况N-10

    最坏情况:元素降序排列,比较次数为0+1+2...+n-1

    最好情况:元素升序排列,比较次数为1*(N-1)

public static void sort(Comparable[] a){
    //将a按升序排列
    int N = a.length;
    for (int i=1; i<N; i++){
        //当前索引为i
        //将a[i]插到a[i-1],a[i-2],a[i-3]...之中
        for (int j=i; j>0&&(a[j].compareTo(a[j-1]))<0; j--){
            //循环交换i 和 0~i-1之间比i小的数
            Comparable t = a[j];
            a[j] = a[j-1];
            a[j-1] = t;
        }
    }
}

对于随机排序的无重复主键的数组,插入排序和选择排序的运行时间都是平方级别的

3. 希尔排序

“对插入排序的改进”:交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。思想是是数组中任意间隔为h的元素都是有序的(h有序数组),对h个子数组内部进行插入排序。

  • 与选择排序和插入排序不同的是,希尔排序也可以用于大型数组

  • 希尔排序比选择排序、插入排序快很多,而且数组越大优势越大

  • 希尔排序的运行时间达不到平方级,最坏情况下比较次数和N^(3/2)成正比。

  • 使用递增序列1,4,13,40,121,364......的希尔排序所需比较次数不会超过N的若干倍乘递增序列长度

public static void sort(Comparable[] a){
    //将a[]按升序排列
    int N = a.length;
    int h = 1;
    while (h<N/3) h=h*3+1;//递增序列1,4,13,40,121,364,1093...
    //插入排序
    while (h>=1){
        //将数组变为h有序
        for (int i=h; i<N; i++){
            for (int j=i; j>=h&&(a[j].compareTo(a[j-h]))<0; j-=h){
                Comparable t = a[j];
                a[j] = a[j-h];
                a[j-h] = t;
            }
        }
        h = h/3;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值