排序算法——堆排序

堆排序

描述:

堆排序利用堆这种数据结构设计的一种排序算法,堆是一个近似完全二叉树的结构,并同时满足堆积的性质。即子节点的键值或索引总是小于(或者大于)它的父节点。

堆排序每次取大顶堆中的最大元素,取出最大元素后,剩余元素重新构成大顶堆,再取最大元素,以此类推。n个元素取n-1次即可完成排序。(小顶堆类似)
在这里插入图片描述

代码如下:

public static void sortAscend(int[] array) {
    int heapSize = array.length;
    //buildMaxHeap方法见下面的堆结构分析
    Heap.buildMaxHeap(array, heapSize);
    for (int i = array.length - 1; i > 0; i--) {
    	//exchange方法交换array数组中第0个和第i个下标的值
        Heap.exchange(array, 0, i);
        heapSize--;
        //maxHeapify见下面的堆结构分析
        Heap.maxHeapify(array, heapSize, 0);
    }
}

算法分析:

第3行buildMaxHeap建立最大堆的时间代价为 O ( n ) O(n) O(n),maxHeapify的时间代价为 O ( lg ⁡ n ) O(\lg{n}) O(lgn),for循环的时间代价为 O ( n lg ⁡ n ) O(n\lg{n}) O(nlgn),堆排序的总的时间代价为 O ( n ) + O ( n lg ⁡ n ) = O ( n lg ⁡ n ) O(n)+O(n\lg{n})=O(n\lg{{n}}) O(n)+O(nlgn)=O(nlgn)。、

时间复杂度: O ( n lg ⁡ n ) O(n\lg{n}) O(nlgn)

空间复杂度: O ( 1 ) O(1) O(1)

堆结构分析

1. maxHeapify分析

维护最大堆性质的重要过程
前提:假定了index的左子树和右子树均为最大堆,此时array[index]可能小于其孩子节点,这违背了最大堆的性质,maxHeapify让array[index]的值在最大堆中逐级下降,使下标为index,根节点的子树重新遵循最大堆的性质

代码如下:

public static void maxHeapify(int[] array, int heapSize, int index) {
    /*获取index儿子节点的下标*/
    int left = index << 1;
    int right = (index << 1) + 1;
    /*获取index 左儿子 右儿子三个节点中值最大节点的下标*/
    int maxIndex = index;
    if (left < heapSize && array[left] > array[index]) {
        maxIndex = left;
    }
    if (right < heapSize && array[right] > array[maxIndex]) {
        maxIndex = right;
    }
    /*最大值节点置于父节点位置*/
    if (maxIndex != index) {
    	//exchange方法交换array数组中第0个和第i个下标的值
        exchange(array, index, maxIndex);
        maxHeapify(array, heapSize, maxIndex);
    }
}

算法分析:

调整index和index的左右子节点的时间代价为 O ( 1 ) O(1) O(1),加上maxHeapify在index孩子节点上运行的时间代价(递归调用的时间代价)。每个孩子节点的子树的大小至多为 2 n / 3 2n/3 2n/3(最坏情况发生在树的最底层恰好半满的时候)。

运行时间:

T ( n ) < = T ( 2 n / 3 ) + O ( 1 ) T(n)<=T(2n/3)+O(1) T(n)<=T(2n/3)+O(1)

根据主定理计算得: T ( n ) = O ( lg ⁡ n ) T(n)=O(\lg{n}) T(n)=O(lgn)

在高度为h的树中,maxHeapify的时间复杂度为 O ( h ) O(h) O(h)

时间复杂度: O ( lg ⁡ n ) O(\lg{n}) O(lgn)

空间复杂度: O ( 1 ) O(1) O(1)

2. buildMaxHeap分析

建立最大堆分析

代码如下:

public static void buildMaxHeap(int[] array, int heapSize) {
    for (int i = (heapSize - 1) / 2; i >= 0; i--) {
        maxHeapify(array, heapSize, i);
    }
}

算法分析:

每次调用maxHeapify需要 O ( log ⁡ n ) O(\log{n}) O(logn),buildMaxHeap需要调用 O ( n ) O(n) O(n)次,因此总的时间复杂度是 O ( n lg ⁡ n ) O(n\lg{n}) O(nlgn),此上界虽正确,但不是渐进紧确的。
不同节点运行maxHeapify的时间与该节点的树高有关,大部分节点的高度都很小,因此可以获得一个更加紧确的界。

运行时间:

包含n个元素的堆的高度为 └ lg ⁡ n ┘ \llcorner\lg{n}\lrcorner lgn,高度为h的堆最多包含 ┌ n / 2 h + 1 ┐ \ulcorner n/2^{h+1}\urcorner n/2h+1个节点。

高度为h的节点上运行maxHeapify的代价是 O ( h ) O(h) O(h),buildMaxHeap的总代价为:

∑ h = 0 └ lg ⁡ n ┘ ┌ n 2 h + 1 ┐ O ( h ) = O ( n ∑ h = 0 └ lg ⁡ n ┘ h 2 h ) \sum_{h=0}^{\llcorner\lg{n}\lrcorner}{\ulcorner \frac{n}{2^{h+1}}\urcorner}O(h)=O(n\sum_{h=0}^{\llcorner\lg{n}\lrcorner}{\frac{h}{2^h}}) h=0lgn2h+1nO(h)=O(nh=0lgn2hh)

∵ ∑ h = 0 ∝ h 2 h = 1 / 2 ( 1 − 1 / 2 ) 2 = 2 \because \sum_{h=0}^{\propto}{\frac{h}{2^h}}=\frac{1/2}{(1-1/2)^2}=2 h=02hh=(11/2)21/2=2

∴ O ( n ∑ h = 0 └ lg ⁡ n ┘ h 2 h ) = O ( n ∑ h = 0 ∝ h 2 h ) = O ( n ) \therefore O(n\sum_{h=0}^{\llcorner\lg{n}\lrcorner}{\frac{h}{2^h}})=O(n\sum_{h=0}^{\propto}{\frac{h}{2^h}})=O(n) O(nh=0lgn2hh)=O(nh=02hh)=O(n)

因此,把一个无序数组构造成一个最大堆需要 O ( n ) O(n) O(n)

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( 1 ) O(1) O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值