排序(二):希尔排序,堆排序

本次介绍:希尔排序,堆排序

一、希尔排序

1.原理 : 希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
① 希尔排序是对直接插入排序的优化。
② 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

下图中颜色相同的数字为同一组,然后对每一组进行插入排序,每次对所有组执行插入结束后,gap = gap/3+1,重新定间隔,重新分组,重复进行插入排序,直到gap = 1,且插入排序执行结束后,排序过程执行结束。
在这里插入图片描述
2.实现(升序):

    public static void shellSort(int[] arr){
    //先对数据进行分组
    //每组数据进行插入排序 逻辑分组
    //同一数据,它们之间的数据间隔不一定是1
        int gap = arr.length;
        while(gap > 1){
            gap = gap / 3 + 1;
            for(int i = 0;i < arr.length - gap;i++) {
                int end = i;
                int key = arr[end + gap];
                while (end >= 0 && arr[end] > key) {
                    arr[end+gap] = arr[end];
                    end -= gap;
                }
                arr[end + gap] = key;
            }
        }
    }

3.性能分析
在这里插入图片描述
4.稳定性 : 不稳定

5.评价 : 希尔排序其实是插入排序的升级版,也是基于插入排序的原理,但是引入了一个分组的概念,也就是gap,先进行多次预排序,当gap=1时,进行最后一次排序,因为有了之前的预排序过程,所以总体移动次数较少,实现了性能的优化。希尔排序的缺点是不稳定,因为分组和插入的缘故可能导致元素的相对位置发生改变,希尔排序是不稳定排序。

二、堆排序

预备知识: ——堆是具有以下性质的完全二叉树:
每个结点的值都大于或等于其左右孩子结点的值,称为大根堆;
或者每个结点的值都小于或等于其左右孩子结点的值,称为小根堆。

1.原理 : 堆排序也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。(前提是先了解堆的概念)
堆排序主要分为两个过程,第一个是建堆过程,第二是排序过程。
注意 : 排升序要建大堆;排降序要建小堆。
①建堆 : 图为建一个大堆的过程
原数组 : {1,6,3,5,7,8}
大根堆 : {8,7,3,5,6,1}
在这里插入图片描述
②排序 :
在这里插入图片描述
上图为一次排序的过程,然后按照此过程从最后一个结点开始依次进行排序,当循环至根节点及排序过程结束。

2.实现(升序) :

    /**
     * 堆排序
     */
    public static void heapSort(int[] arr){
        int len = arr.length;
        //建堆, 最后一个非叶子节点向下调整
        for(int i = (len - 2) / 2; i >= 0;i--){
            shiftDownBig(arr,i,len);
        }
        //交换 向下调整
        //未排序的元素个数
        int end = len - 1;
        while(end > 0){
            swap(arr,0,end);
            shiftDownBig(arr,0,end);
            --end;
        }
    }
	/**
     *大堆的向下调整
     */
    public static void shiftDownBig(int[] arr,int parent,int sz){
        int child = parent * 2 + 1; // left child
        //从parent开始,一直调整到第一子节点结束
        while(child < sz ){
            //right child : child + 1
            if(child+1 < sz && arr[child+1] > arr[child]){
                child++;
            }
            if(arr[child] > arr[parent]){
                //如果child大于parent,向下调整,交换值
                swap(arr,child,parent);
                //更新,继续向下调整
                parent = child;
                child = 2 * parent + 1;
            }
            else{
                //不需要调整
                break;
            }
        }
    }

3.性能分析 :
在这里插入图片描述
4.稳定性 : 不稳定
5.评价 : 堆排序是一种常见的排序方式,因为运用了二叉树,所以堆排序效率提高,时间复杂度为O(n*logn),所以实际应用较多,缺点是由于堆排序有一个建堆的过程所以当数组的数据量较小时不能发挥出堆排序的优势,只有当数据量较大时才能很好的体现出堆排序的优势之处,我们也经常利用堆排序来解决topK问题。
(若有哪里不对之处,还请多多指出)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值