树基础知识
子节点(i)找父节点:(i-1)//2
堆排序过程
代码实现
本文以大根堆(从小到大排序)为例。
向下调整的条件:节点的左右子树都是堆,但整体(包括自身)不是堆。
建堆过程:先找到最后一个非叶子节点,与其叶子节点,先向下调整形成一个小堆。再往前倒二个非叶子节点,也向下调整形成一个小堆…最后整体满足向下调整条件,进行一次向下调整,建堆完成。
堆排序过程:用i指向堆的最后一个叶子节点,与堆顶交换位置。接下来对除了最大值的其他数进行向下调整(因为是与最后一个叶子节点交换,所以不影响堆的结构,依然满足向下调整的条件)。经过一次调整,第二大的数在堆顶,并且指向最后一个叶子节点的i-1,与堆顶交换位置…最后全部交换过后,形成从小到大排序的列表。
def sift(li,low,high): # 向下调整
i = low # 指向父节点
j = 2 * i + 1 # 指向左子节点
tmp = li[low] # 对堆顶进行向下调整
while j<=high: # 子节点要存在
if j+1 <= high and li[j+1] > li[j]: # 右子节点存在 且 大于左子节点则指向右子节点
j = j+1 # 用两个子节点较大的与tmp比较(大根堆)
if li[j] > tmp: # 子节点大于tmp
li[i] = li[j] # 则子节点向上移动
i = j
j = 2 * i + 1 # 继续向下查找调整
else: # 直到两个子节点都小于tmp,所以tmp可以放这
li[i] = tmp
break
else: # 若i已指向叶子节点跳出循环,tmp就放这
li[i] = tmp
def heap_sort(li):
n = len(li)
for i in range((n-1-1)//2,-1,-1): # 建堆,n-1指最后一个叶子节点,(叶子节点-1)//2找到父节点。
sift(li,i,n-1) # i是所有小堆父节点,这边统一用n-1可以省去每次求小堆的high
for i in range(n-1,-1,-1): # 排序,i指向当前堆最后一个叶子节点
li[0],li[i] = li[i],li[0] # 最后一个叶子节点和堆顶交换
sift(li,0,i-1) # 现在节点左右均为堆,进行一次向下调整
li = [9,5,2,4,1,7,6,3,8]
print(li)
heap_sort(li)
print(li)
堆排序时间复杂度:O(nlogn)
Python堆的内置模块
heapq.heapify(li) 建(小根)堆
heapq.heappop(li) 弹出最小值(堆顶)
heapq相关函数:
‘heapify’:将一个列表转化为堆 (Transform list into a heap)
‘heappop’:pop最小的item,保持堆不变(Pop the smallest item off the heap, maintaining the heap invariant.)
‘heappush’:heappush(heap, item) 压入item,保持堆不变( Push item onto heap, maintaining the heap invariant.)
‘heappushpop’:heappushpop(heap, item),先heappush(item),再headpop最小元素
‘heapreplace’:heapreplace(heap, item) ,返回最小元素,添加item
‘merge’:heapq.merge(*iterables, key=None, reverse=False) ,合并多个列表为有序列表
‘nlargest’:heapq.nlargest(n, iterable, key=None),寻找列表中最大的n个元素
‘nsmallest’:heapq.nsmallest(n, iterable, key=None),寻找列表中最小的n个元素
————————————————
版权声明:本文为CSDN博主「frostjsy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013069552/article/details/107350595