赞
踩
堆排序思想:堆顶(小顶堆)的元素是整个堆中最小的元素,将堆顶元素与最后一个元素交换,然后用一次‘向下筛选’将新的堆顶元素移动到堆中正确的位置:即比较堆顶元素与其两个左右子结点的大小,如果堆顶元素最小,则将其保留在堆顶位置,停止;如果左子结点或右子结点最小,则交换堆顶元素与左子结点或右子结点的值,然后再沿着当前路径不断地比较下去,直至最初的堆顶元素在某一次比较中是最小值或者到达叶结点位置。
此外,如果是小顶堆,得到的是降序序列;如果是大顶堆,得到的是升序序列。
下面用图来解释堆排序的具体过程:
假设最初的无序的列表为[5,6,8,1,2,4,9],经过堆的初始化操作后得到的对堆结构如下:
然后开始进行堆排序,每次都交换堆顶和末尾元素,然后对堆顶元素进行一次向下筛选,带颜色区域为已经排好序的位置,过程如下:
- def heap_sort(elems):
- def siftdown(elems, e, begin, end): #向下筛选
- i, j = begin, begin*2+1 #j为i的左子结点
- while j < end:
- if j+1 < end and elems[j] > elems[j+1]: #如果左子结点大于右子结点
- j += 1 #则将j指向右子结点
- if e < elems[j]: #j已经指向两个子结点中较小的位置,
- break #如果插入元素e小于j位置的值,则为3者中最小的
- elems[i] = elems[j] #能执行到这一步的话,说明j位置元素是三者中最小的,则将其上移到父结点位置
- i, j = j, j*2+1 #更新i为被上移为父结点的原来的j的位置,更新j为更新后i位置的左子结点
- elems[i] = e #如果e已经是某个子树3者中最小的元素,则将其赋给这个子树的父结点
- #或者位置i已经更新到叶结点位置,则将e赋给这个叶结点。
-
- end = len(elems)
- for i in range(end//2-1, -1, -1): #构造堆序。
- siftdown(elems, elems[i], i, end)
- for i in range ((end-1), 0,-1): #进行堆排序.i最后一个值为1,不需要到0
- print(elems)
- e = elems[i] #将末尾元素赋给e
- elems[i] = elems[0] #交换堆顶与最后一个元素
- siftdown(elems, e, 0, i)
-
- return(elems)
-
- if __name__=="__main__":
- print(heap_sort([5,6,8,1,2,4,9]))
将无序的序列构造为堆序需要O(n)时间。第二个循环共n次,每次都将新的堆顶元素进行一次向下筛选,堆顶元素下移的距离不会超过log n,所以第二个循环的时间复杂度为O(nlog n)。整个堆排序的时间复杂度为O(nlog n),其空间复杂度为O(1)。当元素个数较少时,堆排序的大部分时间花在了堆的初始化和向下筛选上,当元素较多时,具有较好的效率。
参考:点击打开链接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。