文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

浅析经典排序算法之堆排序

2024-12-03 13:00

关注

堆是一棵完全二叉树

节点总是大于(或小于)它的孩子节点。

因此,根据第二个特性,就把二叉堆分为大顶堆(或叫最大堆),和小顶堆(或叫最小堆)。

在上图中,1 2 是大顶堆 ,3 4 是小顶堆。判断是不是堆的条件:「从根结点到任意结点路径上结点序列的有序性!大顶堆和小顶堆判断序列是顺序还是逆序!」

Python并没有提供“堆”这种数据类型,它是直接把列表当成堆处理的。Python提供的heapq包中有一些函数,提供执行堆操作的工具函数

  1. >>> import heapq 
  2. >>> heapq.__all__ 
  3. ['heappush''heappop''heapify''heapreplace''merge''nlargest''nsmallest''heappushpop'

堆排序

往堆中插入一个元素后,我们就需要进行调整,让其重新满足堆的特性,这个过程叫做堆化(heapify)。

那么堆排序的基本思路是怎么样的呢?

  1. 将待排序序列构建成一个堆 H[0……n-1],根据(升序降序需求)选择大顶堆或小顶堆;
  2. 把堆首(最大值)和堆尾互换;
  3. 顺着节点所在的路径,向上或者向下,对比,然后交换,目的是把新的数组顶端数据调整到相应位置;

下面举个例子(资源来自王争算法),比如在上面的大顶堆中添加数据22。


堆化非常简单,就是顺着节点所在的路径,向上或者向下,对比,然后交换。

堆排序的删除操作,这里一般指的是堆顶元素,当我们删除堆顶元素之后,就需要把第二大的元素放到堆顶,那第二大元素肯定会出现在左右子节点中。

然后我们再迭代地删除第二大节点,以此类推,直到叶子节点被删除。但是这样会产生一个数组空洞的问题。


因此,这里面又个技巧,就是删除堆顶元素的时候,不能直接删除,要用堆顶元素和最后一个元素做交换,然后根据堆的特点调整堆,直到满足条件。

排序的过程就是每次待排序的序列长度减去1再执行这两步。

下面给出通过Python中的heapq模块实现的堆排序简单代码。

  1. from heapq import heappop, heappush 
  2.  
  3. def heap_sort(array): 
  4.     heap = [] 
  5.     for element in array: 
  6.         heappush(heap, element) 
  7.  
  8.     ordered = [] 
  9.  
  10.     while heap: 
  11.         ordered.append(heappop(heap)) 
  12.     return ordered 
  13.  
  14. array = [13, 21, 15, 5, 26, 4, 17, 18, 24, 2] 
  15. print(heap_sort(array)) 
  16. # [2, 4, 5, 13, 15, 17, 18, 21, 24, 26] 

如果不使用heapq模块,对于推排序需要了解堆排序中的建堆过程。

将数组原地建成一个堆。不借助另一个数组,就在原数组上操作。建堆的过程,有两种思路。

第一种建堆思路的处理过程是从前往后处理数组数据,并且每个数据插入堆中时,都是从下往上堆化。而第二种实现思路,是从后往前处理数组,并且每个数据都是从上往下堆化。


也就是如果节点的下标是 i,那左子节点的下标就是 2∗i+1,右子节点的下标就是 2∗i+2,父节点的下标就是 。

  1. def heap_sort(array): 
  2.     n = len(array) 
  3.     # 从尾部开始建堆,这样保证子节点有序 
  4.     for i in range((n-1)//2, -1, -1): 
  5.         _shift(array, n, i) 
  6.     # 依次把堆顶元素交换到最后,重建堆顶(堆不包含刚交换的最大元素) 
  7.     for i in range(n-1, 0, -1): 
  8.         array[0], array[i] = array[i], array[0] 
  9.         _shift(array, i, 0) 
  10.     return array 
  11.  
  12. # 重建堆顶元素 n:堆元素个数,i:堆建顶位置 
  13. def _shift(array, n, i): 
  14.     # 如果没有子节点,直接返回 
  15.     if i*2+1 >= n: 
  16.         return 
  17.     # 取最大子节点位置 
  18.     maxsub = i*2+2 if i*2+2 < n and array[i*2+1] <= array[i*2+2] else i*2+1 
  19.     # 如果节点小于最大子节点,交换元素,递归以子节点为堆顶重建 
  20.     if array[i] < array[maxsub]: 
  21.         array[i], array[maxsub] = array[maxsub], array[i] 
  22.         _shift(array, n, maxsub) 
  23.  
  24. if __name__ == '__main__'
  25.     array = [13, 21, 15, 5, 26, 4, 17, 18, 24, 2] 
  26.     print(heap_sort(array)) 
  27.      
  28. # [2, 4, 5, 13, 15, 17, 18, 21, 24, 26] 

堆排序不是稳定的排序算法,因为在排序的过程,存在将堆的最后一个节点跟堆顶节点互换的操作,所以就有可能改变值相同数据的原始相对顺序。堆排序整体的时间复杂度是O(nlogn)  。

参考资料 https://github.com/MaoliRUNsen/runsenlearnpy100

 

来源:Python之王内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯