堆排序。Java泛型实现推排序。

前言基础:

1、堆排序的时间复杂度为O(nlogn),空间复杂度为O(1)。

2、推排序是不稳定的排序算法。

3、每次排序保证了后i个元素是有序的,第后i个元素所在的位置是其最后所在的位置,每次将区域内最大的元素放在倒数第i个位置上。

4、堆排序大致分为整理堆排序两个过程。

下述代码都是索引从0开始的,所以:

1、双亲节点:(i-1)/2。

2、左孩子:2*i+1。

3、右孩子:2*i+2.

4、是否为叶子节点的条件  2 * i + 1 < n 或  2 * i + 2 <= n   (n为数组的长度)

如果索引下标从1开始 :

大顶堆的性质 

1、最大的元素是数组的第一个元素。

2、实现的底层是一个完全二叉树。

3、每一个孩子节点的值都小于其父节点的值。

4、保证了父节点的值一定大于子节点,但是层数之间没有明显的大小关系。如下图13在第三层但是其比第四层的17小。

5、添加元素:每次只将元素添加到最后,然后不断上浮整理堆。

6、删除元素:只能取出堆顶,即最大的元素。然后将最后一个元素赋值给第一个元素,最后对该元素进行下沉整理堆。 


整理堆 

从第一个非叶子节点开始,向前整理,并用该节点与其两个孩子节点进行比较,如果该双亲节点比其最大的孩子节点小,就交换二者的位置。直到该节点大于两个孩子节点的值或该节点是叶子节点。

排序

每次排序的时候取出[0,i]中第一个元素,即最大的元素也叫堆顶,其与数组倒数第i个元素进行交换,然后再次对堆进行整理,保证大顶堆每次取出元素之后仍然在[0,n-i]上保持大顶堆的性质。

代码:

public class HeapSort {
    public HeapSort() {
    }
    //时间复杂度是O(nlogn)
    public static <E extends Comparable<E>> void sort(E arr[]) {
        if(arr.length<=1) return;
        //从第一个非叶子节点的元素开始进行堆整理。
    /*arr.length-2解释:
    * 因为某个节点的双亲是(i-1)/2,所以设该i就是数组中的最后一个元素,即arr.lenth-1,所以其双亲为(arr.length-1-1)/2
    */
        for (int i = (arr.length - 2) / 2; i >= 0; i--) {
            sitDown(arr, i, arr.length);
        }
        //将元素添加到原数组,并且不断构建堆
        for (int i = arr.length - 1; i >= 0; i--) {
            Util.swap(arr, 0, i);
            sitDown(arr, 0, i);
        }
    }

    private static <E extends Comparable<E>> void sitDown(E[] arr, int i, int n) {
        while (2 * i + 1 < n) {
            int left = 2 * i + 1;
            //找到左右孩子最大的那个索引的下标,最终的left指向的就是要交换的那个孩子的索引
            if (left + 1 < n && arr[left].compareTo(arr[left + 1]) < 0)
                left++;

            //如果其比最大的那个还要大,则不需要交换了,直接退出
            if (arr[i].compareTo(arr[left]) >= 0)
                break;
            //否则执行交换逻辑
            Util.swap(arr, i, left);
            //让i等于应该交换的那个元素的下标
            i = left;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值