堆排序(python)

系统 1701 0

6.堆排序

6.1算法思想

堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子结点的键值或索引总是小于(或者大于)它的父节点(同层节点不进行比较)。并且一般来说,升序排列通过构造大顶堆来实现,降序排列通过构造小顶堆来实现。
这种算法不用额外的空间,空间复杂度为o(1),时间复杂度为o(nlogn)

6.1.1堆

堆是一种完全二叉树(完全二叉树 是 一种除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐的树)
堆有两种类型: 大顶堆和小顶堆:
大顶堆:每个结点的值都大于或等于左右孩子结点
小顶堆:每个结点的值都小于或等于左右孩子结点

大顶堆和小顶堆可以通过下面的图进行直观的感受:
堆排序(python)_第1张图片
堆排序(python)_第2张图片

6.2 算法过程

  1. 首先将待排序的数组构造出一个大顶堆(这里以升序排列为例)
  2. 取出这个大顶堆的堆顶节点(最大值),与堆的最下最右的元素进行交换,然后把剩下的元素再构造出一个大根堆。
  3. 重复第二步,直到这个大根堆的长度为1,此时完成排序
ps:将数组中的元素构造成大顶堆的时候,堆顶元素就是所有元素的最大值,而堆的最下最右是数组的最后一个元素,这就相当于把最大值放在了数组的最后,然后在对剩下的元素进行相同操作。

对于这个算法的具体过程的图示,大家可以看一下堆排序图解这篇博客。

过程动图如下

6.3 python代码

6.3.1 递归(不对原数组引入一个辅助元素)
            
              
                global
              
               length  
              
                # 定义全局变量
              
              
                def
              
              
                buildMaxHeap
              
              
                (
              
              numList
              
                )
              
              
                :
              
              
                # 构建最大堆,
              
              
                global
              
               length
    length 
              
                =
              
              
                len
              
              
                (
              
              numList
              
                )
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              length
              
                //
              
              
                2
              
              
                ,
              
              
                -
              
              
                1
              
              
                ,
              
              
                -
              
              
                1
              
              
                )
              
              
                :
              
              
                # 从最后一个有子节点的根节点节点开始构建的时候从下往上,从右向左构建
              
              
        heapify
              
                (
              
              numList
              
                ,
              
              i
              
                )
              
              
                def
              
              
                heapify
              
              
                (
              
              numList
              
                ,
              
              i
              
                )
              
              
                :
              
              
                # 堆调整,将剩下的元素调整成最大堆
              
              
                global
              
               left
              
                ,
              
              right
              
                ,
              
              largest
              
                ,
              
              length
    leftChildren 
              
                =
              
              
                2
              
              
                *
              
               i 
              
                +
              
              
                1
              
              
    rightChildren 
              
                =
              
              
                2
              
              
                *
              
               i 
              
                +
              
              
                2
              
              
    largest 
              
                =
              
               i
    
              
                if
              
               leftChildren 
              
                <
              
               length 
              
                and
              
               numList
              
                [
              
              leftChildren
              
                ]
              
              
                >
              
               numList
              
                [
              
              largest
              
                ]
              
              
                :
              
              
                # leftChildren < length先判断是否有子节点,因为python数组下标从零开始的缘故,下标为length/2的元素可能会没有子节点。
              
              
        largest 
              
                =
              
               leftChildren
    
              
                if
              
               rightChildren 
              
                <
              
               length 
              
                and
              
               numList
              
                [
              
              rightChildren
              
                ]
              
              
                >
              
               numList
              
                [
              
              largest
              
                ]
              
              
                :
              
              
        largest 
              
                =
              
               rightChildren
    
              
                if
              
               largest 
              
                !=
              
               i
              
                :
              
              
                # 如果largest(最大的节点所在的下标),不是根节点,说明这三个借点不满足堆的规则,
              
              
                # 需要进行调整,根节点的下标是i,最大节点的下标是largest,交换即可。
              
              
        swap
              
                (
              
              numList
              
                ,
              
              i
              
                ,
              
              largest
              
                )
              
              
                # 当当前的根节点和子节点满足堆的关系之后,由子节点作为根节点的树可能又不满足了,必须在对下一层的树进行检查和调整。
              
              
        heapify
              
                (
              
              numList
              
                ,
              
              largest
              
                )
              
              
                def
              
              
                swap
              
              
                (
              
              numList
              
                ,
              
              i
              
                ,
              
              j
              
                )
              
              
                :
              
              
    numList
              
                [
              
              i
              
                ]
              
              
                ,
              
              numList
              
                [
              
              j
              
                ]
              
              
                =
              
               numList
              
                [
              
              j
              
                ]
              
              
                ,
              
              numList
              
                [
              
              i
              
                ]
              
              
                def
              
              
                heapSort
              
              
                (
              
              numList
              
                )
              
              
                :
              
              
                global
              
               length
    buildMaxHeap
              
                (
              
              numList
              
                )
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                len
              
              
                (
              
              numList
              
                )
              
              
                -
              
              
                1
              
              
                ,
              
              
                0
              
              
                ,
              
              
                -
              
              
                1
              
              
                )
              
              
                :
              
              
        swap
              
                (
              
              numList
              
                ,
              
              
                0
              
              
                ,
              
              i
              
                )
              
              
        length 
              
                -=
              
              
                1
              
              
                # 在调整的时候就不会在调整最后一个元素了
              
              
        heapify
              
                (
              
              numList
              
                ,
              
              
                0
              
              
                )
              
              
                # 由于交换之前,已经都调整为最大堆了,而交换之后,大部分都符合堆的规则,
              
              
                # 只从堆顶元素(下标为1)开始,只进行局部的调整就好,
              
              
                # 这时候不用再像刚开始构建最大堆一样从下往上,从右往左调整交换了。
              
              
                return
              
               numList
numlist 
              
                =
              
              
                [
              
              
                4
              
              
                ,
              
              
                5
              
              
                ,
              
              
                4
              
              
                ,
              
              
                1
              
              
                ,
              
              
                8
              
              
                ,
              
              
                7
              
              
                ,
              
              
                2
              
              
                ,
              
              
                6
              
              
                ,
              
              
                3
              
              
                ]
              
              
                print
              
              
                (
              
              heapSort
              
                (
              
              numlist
              
                )
              
              
                )
              
            
          
6.3.2非递归(引入一个辅助因素,将数组的下标往后加1)
            
              
                def
              
              
                swap
              
              
                (
              
              arr
              
                ,
              
              i
              
                ,
              
              j
              
                )
              
              
                :
              
              
    arr
              
                [
              
              i
              
                ]
              
              
                ,
              
              arr
              
                [
              
              j
              
                ]
              
              
                =
              
               arr
              
                [
              
              j
              
                ]
              
              
                ,
              
              arr
              
                [
              
              i
              
                ]
              
              
                def
              
              
                heapAdjust
              
              
                (
              
              arr
              
                ,
              
              start
              
                ,
              
              end
              
                )
              
              
                :
              
              
    i 
              
                =
              
               start
    temp 
              
                =
              
               arr
              
                [
              
              start
              
                ]
              
              
    j 
              
                =
              
              
                2
              
              
                *
              
               i
    
              
                while
              
               j 
              
                <=
              
               end
              
                :
              
              
                if
              
               j 
              
                <
              
               end 
              
                and
              
               arr
              
                [
              
              j
              
                ]
              
              
                <
              
               arr
              
                [
              
              j
              
                +
              
              
                1
              
              
                ]
              
              
                :
              
              
            j 
              
                +=
              
              
                1
              
              
                if
              
               arr
              
                [
              
              i
              
                ]
              
              
                <
              
               arr
              
                [
              
              j
              
                ]
              
              
                :
              
              
            arr
              
                [
              
              i
              
                ]
              
              
                =
              
               arr
              
                [
              
              j
              
                ]
              
              
            i 
              
                =
              
               j
            j 
              
                =
              
              
                2
              
              
                *
              
               i
        
              
                else
              
              
                :
              
              
                break
              
              
    arr
              
                [
              
              i
              
                ]
              
              
                =
              
               temp

              
                def
              
              
                heapSort
              
              
                (
              
              numList
              
                )
              
              
                :
              
              
    numList
              
                .
              
              insert
              
                (
              
              
                0
              
              
                ,
              
              
                0
              
              
                )
              
              
                # 由于python,数组的下标从0开始,因此需要加入一个辅助元素,是所有的元素的下标都往后移动一位。
              
              
    length 
              
                =
              
              
                len
              
              
                (
              
              numList
              
                )
              
              
                -
              
              
                1
              
              
    firstAdjustRoot 
              
                =
              
               length 
              
                //
              
              
                2
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              firstAdjustRoot
              
                )
              
              
                :
              
              
                # 在构造最大堆的时候,不会对最左侧的0进行处理,因为i不会取到firstAdjustRoot。
              
              
        heapAdjust
              
                (
              
              numList
              
                ,
              
              firstAdjustRoot
              
                -
              
              i
              
                ,
              
              length
              
                )
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              length
              
                -
              
              
                1
              
              
                )
              
              
                :
              
              
        swap
              
                (
              
              numList
              
                ,
              
              
                1
              
              
                ,
              
              length
              
                -
              
              i
              
                )
              
              
                # 由于大顶堆的堆顶元素是最大的,把它和数组最后的元素(堆的最下层最右元素)
              
              
                # 进行互换,就相当于把最大值放在了最后,下一次,把最后一个元素撇出来,对剩下来的在排序
              
              
        heapAdjust
              
                (
              
              numList
              
                ,
              
              
                1
              
              
                ,
              
              length
              
                -
              
              i
              
                -
              
              
                1
              
              
                )
              
              
                # 由于交换之前,已经都调整为最大堆了,而交换之后,大部分都符合堆的规则,
              
              
                # 只从堆顶元素(下标为1)开始,只进行局部的调整就好,
              
              
                # 这时候不用再像刚开始构建最大堆一样从下往上,从右往左调整交换了。
              
              
                return
              
              
                [
              
              numList
              
                [
              
              i
              
                ]
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              
                1
              
              
                ,
              
              
                len
              
              
                (
              
              numList
              
                )
              
              
                )
              
              
                ]
              
              
numlist 
              
                =
              
              
                [
              
              
                50
              
              
                ,
              
              
                16
              
              
                ,
              
              
                30
              
              
                ,
              
              
                10
              
              
                ,
              
              
                60
              
              
                ,
              
              
                90
              
              
                ,
              
              
                2
              
              
                ,
              
              
                80
              
              
                ,
              
              
                70
              
              
                ]
              
              
                print
              
              
                (
              
              heapSort
              
                (
              
              numlist
              
                )
              
              
                )
              
            
          

参考文章

有辅助元素的堆排序
https://www.cnblogs.com/chengxiao/p/6129630.html
https://www.cnblogs.com/onepixel/articles/7674659.html


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论