排序(1)


1. 选择排序

将第i小的元素放在第i个位置

// 选择排序,将第i小的元素放在a[i]上
    public static void selectionSort(Comparable[] a) {
        for (int i = 0; i < a.length; i++) {
            int min = i;
            for (int j = i + 1; j < a.length; j++)
                if (less(a[j], a[min]))
                    min = j;
            if (min == i)// 如果自己就是最小的则不用交换,跳过
                continue;
            exchange(a, min, i);
        }
    }

大约需要n²/2次比较n²/2次交换
选择排序时间主要花费在比较上,我后面使用了一个判断语句避免了不必要的交换


2. 插入排序

将一个新元素插入到已经排好序的数组中
主要是消除逆序组合
更加适用于部分有序数组

// 插入排序,将一个新的元素插入到已经排好序的数组中,边比较边交换
    public static void insertionSort(Integer[] a) {
        for (int i = 1; i < a.length; i++)
            for (int j = i; j >= 1 && less(a[j], a[j - 1]); j--)// 将比较放在条件里可以减少比较次数
                exchange(a, j, j - 1);// 交换相邻的2个元素
    }

    // 将较大的元素直接后移,腾出一个位置
    public static void insertionSort1(Integer[] a) {
        for (int i = 1; i < a.length; i++) {
            int j = i;
            Integer temp = a[j];// 保存当前元素
            while (j > 0 && less(temp, a[j - 1])) {
                a[j] = a[j - 1];// 元素后移
                j--;
            }
            a[j] = temp;
        }
    }

具体有2种实现方法:

  1. 一直交换
  2. 一直后移元素,找到位置后直接插入

对于第1种方法:

情况比较次数交换次数
平均情况n²/4n²/4
最坏情况n²/2n²/2
最好情况n-10

最后通过代码验证,第2种方法效率更高


3. 希尔排序

是一种插入排序的变体,仅仅增加了几行代码,效率大大提升
插入排序只能一次移动一个距离,而希尔排序可以移动很远的距离
希尔排序的思想:使数组任意间隔为h的元素都是有序的

分成了多个插入排序的过程,依次王每个数组中插入新元素,最后一次总是1-sorted.

h递增序列的选择很重要,一般选择3 * h + 1(兼顾奇偶)

// 希尔排序,基于插入排序的快速排序算法,不断地使部分有序,消除逆序数
    public static void shellSort(Comparable[] a) {
        int h = 1;
        while (h < a.length / 3)
            h = 3 * h + 1;// 递增序列: 1, 4, 13, 40······
        while (h >= 1) {
            for (int i = h; i < a.length; i++)
                for (int j = i; j >= h && less(a[j], a[j - h]); j -= h)// 因为是向前遍历,所以这里的条件是>=h,不然-h就会下标越界
                    exchange(a, j, j - h);
            h /= 3;// 不断地缩小局部间隔
        }
    }

    // 使用选择排序的希尔排序
    public static void shellSort1(Integer[] a) {
        int h = 1;
        while (h < a.length / 3)
            h = 3 * h + 1;
        while (h >= 1) {
            for (int i = 0; i < a.length - h; i++) {
                int min = i;
                for (int j = i + h; j < a.length; j += h)
                    if (less(a[j], a[min]))
                        min = j;
                if (min == i)// 如果自己就是最小的则不用交换,跳过
                    continue;
                show(a, min, i);
                exchange(a, min, i);
            }
            h /= 3;
        }
        show(a, -1, -1);
    }

最后,上2个辅助方法:

// 将对象数组a中的i1,i2个对象交换位置
    public static void exchange(Comparable[] a, int i1, int i2) {
        Comparable temp = a[i1];
        a[i1] = a[i2];
        a[i2] = temp;
    }

    // a是否小于b
    public static boolean less(Comparable a, Comparable b) {
        return a.compareTo(b) < 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值