问题:
现在有 n 个数,设计算法得到前 k 大的数。(k<n)
解决思路:
- 排序后切片 O(nlogn)
- 排序LowB三人组(冒泡、选择、插入)O(kn)
- 堆排序思路 O(nlogk)
堆排序解决思路
- 取列表前K个元素建立一个小根堆。堆顶就是目前第k大的数。
- 依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素;如果大于堆顶,则将堆顶更换为该元素,并且对堆进行依次调整。
- 遍历列表所有元素后,倒序弹出堆顶。
代码实现
def heapify(tree, low, high):
"""
向下调整(大根堆:父节点小于两个孩子节点),维持堆的性质
:param tree: 完全二叉树列表
:param low: 堆顶元素
:param high: 最后一个位置的元素
"""
i = low
j = 2 * i + 1
tmp = tree[low]
result = []
while j <= high:
if j + 1 <= high and tree[j + 1] < tree[j]:
j = j + 1
if tree[j] < tmp:
tree[i] = tree[j]
i = j
j = 2 * i + 1
else:
break
tree[i] = tmp
def topk_heap(tree, k):
head = tree[0:k]
parent = (k - 2) // 2
# 1.建堆
for i in range(parent, -1, -1):
heapify(head, i, k - 1)
# 2.遍历
for i in range(k, len(tree)):
if tree[i] > head[0]:
head[0] = tree[i]
heapify(head, 0, k - 1)
# 3.出数
for i in range(k - 1, -1, -1):
head[0], head[i] = head[i], head[0]
heapify(head, 0, i - 1)
return head
import random
if __name__ == '__main__':
li = list(range(100))
random.shuffle(li) # 打乱 li 列表的顺序
print(topk_heap(li, 10))