Java关于排序的介绍3-高级排序

本篇博客主要是介绍-希尔排序快速排序

希尔排序
希尔排序是基于插入排序(关于插入排序的介绍请查看简单排序)。
希尔排序主要是解决了插入排序复制次数太多的问题。例如对一个序列进行从小到大的排序,如果有一个很小的数据在序列的末尾,那么当对该数据进行操作的时候,他左边已经有序的数据需要进行大量的进行右移复制操作。希尔排序会选择一个合理的间隔,开始进行排序,这样实现了数据的大跨度移动,就避免了大量数据的复制操作。
关键点间隔(h)的计算
这个地方不做详细介绍,感兴趣的同学请自行查看相关书籍
- java数据结构和算法
- 算法
这里使用 h=3*h+1 来计算间隔
下面看代码

public static void sort(int arr[]) {
        int size = arr.length; // 获取数组大小
        int h = 1; // 间隔
        // 计算间隔
        while (h < size / 3) {
            h = h * 3 + 1;
        }
        while (h > 0) {
            // 对h间隔组成的数据进行排序
            for (int i = h; i < size; i++) {
                int j = i;
                int temp = arr[i];
                // 进行判断 将比当前位置大的数据进行移动
                while (j > h - 1 && arr[j - h] > temp) {
                    arr[j] = arr[j - h];
                    j -= h;
                }
                arr[j] = temp; // 将当前这次排序的标记数据进行移动
            }
            h = (h - 1) / 3; // 修改间隔
        }
    }

快速排序
快速排序的一个关键理解点是划分算法,还有要注意关键字的选择
下面看代码

    /**
     * 排序
     * @param arrs 数组
     * @param left 左边边界
     * @param right 右边边界
     */
    public static void sort(int arrs[], int left, int right) {
        if (left >= right) {
            return;
        }
        int x = arrs[right]; // 选取特定值 选择每一组里面的最后一个元素作为特定值
        int leftPtr = divide(arrs, x, left, right); // 进行一次划分 结果 特定值左边都是小于特定值的数,特定值右边的都是大于特定值的数
        // 再次进行排序 不必要在对上次特定值进行处理
        sort(arrs, left, leftPtr - 1); 
        sort(arrs, leftPtr + 1, right);
    }

    /**
     * 划分
     * @param arrs 数组
     * @param x 特定值
     * @param left 左边边界
     * @param right 右边边界
     * @return 特定值的位置
     */
    private static int divide(int arrs[], int x, int left, int right) {
        int leftPtr = left - 1;
        int rightPtr = right;
        while (true) {
            while (arrs[++leftPtr] > x);// 从左边第一个元素开始,顺序查找到第一个比特定值大的数
            while (rightPtr > 0 && arrs[--rightPtr] < x); // 从倒数第二个元素开始,顺序查找到第一个比特定值小的数
            if (leftPtr >= rightPtr) { // 已经划分完成
                break;
            }
            // 进行交换 
            swap(arrs, leftPtr, rightPtr);
        }
        // 交换特定值到合适的位置
        swap(arrs, leftPtr, right);
        return leftPtr;
    }

    /**
    * 交换数组里面俩个位置的值
    * arrs 数据源
    * leftPtr 左边索引
    * rightPtr 右边的索引
    */
    private static void swap(int[] arrs, int leftPtr, int rightPtr) {
        int temp = arrs[leftPtr];
        arrs[leftPtr] = arrs[rightPtr];
        arrs[rightPtr] = temp;
    }

其中divide就是实现了划分的方法
关于特定值的选择,本例是用每次划分的最后一个元素作为特定值,也有使用从第一个数、中间的一个数、末尾的一个数取一个中间的数作为特定值的。

关于排序的介绍系列博客就结束,在博客的结尾给出关于各个排序的时间复杂度
简单排序 - O(N^2)
归并排序 - O(N*logN)
希尔排序 - O(N*(logN)^2)
快速拍戏 - O(N*logN)

简单排序里面虽然时间复杂度都一样,但是一般情况下
冒泡 > 选择 > 插入
冒泡每次比较以后都需要进行数据交换操作。
归并排序的缺点需要新开辟一个与被排序的数组等大的数组空间。
希尔排序是基于插入排序的主要是减少数据复制次数,实现了数据的大跨度移动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值