当前位置:   article > 正文

学习笔记-图解堆排序(Python实现)_python 堆的关键字排序

python 堆的关键字排序

堆排序思想:堆顶(小顶堆)的元素是整个堆中最小的元素,将堆顶元素与最后一个元素交换,然后用一次‘向下筛选’将新的堆顶元素移动到堆中正确的位置:即比较堆顶元素与其两个左右子结点的大小,如果堆顶元素最小,则将其保留在堆顶位置,停止;如果左子结点或右子结点最小,则交换堆顶元素与左子结点或右子结点的值,然后再沿着当前路径不断地比较下去,直至最初的堆顶元素在某一次比较中是最小值或者到达叶结点位置。

此外,如果是小顶堆,得到的是降序序列如果是大顶堆,得到的是升序序列

下面用图来解释堆排序的具体过程:

假设最初的无序的列表为[5,6,8,1,2,4,9],经过堆的初始化操作后得到的对堆结构如下:

                     

然后开始进行堆排序,每次都交换堆顶和末尾元素,然后对堆顶元素进行一次向下筛选,带颜色区域为已经排好序的位置,过程如下:










  1. def heap_sort(elems):
  2. def siftdown(elems, e, begin, end): #向下筛选
  3. i, j = begin, begin*2+1 #j为i的左子结点
  4. while j < end:
  5. if j+1 < end and elems[j] > elems[j+1]: #如果左子结点大于右子结点
  6. j += 1 #则将j指向右子结点
  7. if e < elems[j]: #j已经指向两个子结点中较小的位置,
  8. break #如果插入元素e小于j位置的值,则为3者中最小的
  9. elems[i] = elems[j] #能执行到这一步的话,说明j位置元素是三者中最小的,则将其上移到父结点位置
  10. i, j = j, j*2+1 #更新i为被上移为父结点的原来的j的位置,更新j为更新后i位置的左子结点
  11. elems[i] = e #如果e已经是某个子树3者中最小的元素,则将其赋给这个子树的父结点
  12. #或者位置i已经更新到叶结点位置,则将e赋给这个叶结点。
  13. end = len(elems)
  14. for i in range(end//2-1, -1, -1): #构造堆序。
  15. siftdown(elems, elems[i], i, end)
  16. for i in range ((end-1), 0,-1): #进行堆排序.i最后一个值为1,不需要到0
  17. print(elems)
  18. e = elems[i] #将末尾元素赋给e
  19. elems[i] = elems[0] #交换堆顶与最后一个元素
  20. siftdown(elems, e, 0, i)
  21. return(elems)
  22. if __name__=="__main__":
  23. print(heap_sort([5,6,8,1,2,4,9]))

将无序的序列构造为堆序需要O(n)时间。第二个循环共n次,每次都将新的堆顶元素进行一次向下筛选,堆顶元素下移的距离不会超过log n,所以第二个循环的时间复杂度为O(nlog n)。整个堆排序的时间复杂度为O(nlog n),其空间复杂度为O(1)。当元素个数较少时,堆排序的大部分时间花在了堆的初始化和向下筛选上,当元素较多时,具有较好的效率。

参考:点击打开链接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/306104
推荐阅读
相关标签
  

闽ICP备14008679号