python-排序算法(三)、堆排序_simpleyako的博客-CSDN博客
---------海量数据中找出前k大数(topk问题)
应用场景
通常在后端开发中,如果想要在若干个话题中,取出前100个最热的话题出来,这时我们就会涉及到topk问题,通常对于这种问题,我第一时间想到的可能就是对若干个话题进行排序之后切片出来。
下面通过堆排序实现方法和冒泡排序方法进行比较:
计算执行时间的装饰器:
def cal_time(func):
def inner(*args, **kwargs):
strat = time.time()
result = func(*args, **kwargs)
end = time.time()
print('%s执行时间:%s' % (func.__name__, end - strat))
return result
return inner
1、堆排序实现
1)解决思路
- 取列表k个元素建立一个小根堆后堆顶就是目前第K大的数。
- 依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素 如果大于堆顶,则将堆顶更换为该元素,并且对堆进行一次向下调整
- 最后遍历列表所有元素后,倒序弹出堆顶
2、代码实现
# 堆的向下调整函数
def shit(li, low, height):
i = low # i指向堆顶的位置
j = i * 2 + 1 # j目前指向i的右孩子的位置
tmp = li[low] # tmp等于当前堆顶元素
while j <= height:
if j + 1 <= height and li[j + 1] < li[j]:
j = j + 1
if li[j] < tmp:
li[i] = li[j]
i = j # i 指向第二层(左边或右边)的子树的堆顶
j = i * 2 + 1
else:
break # 如果右孩子或者左孩子不大于tmp则循环退出
li[i] = tmp
# 实现topk
@cal_time
def heap_sort_topk(li, k):
heap = li[0:k]
# 1、建立小根堆
for i in range((k - 2) // 2, -1, -1):
shit(heap, i, k - 1)
# 2、拿堆顶与后面的元素对比
for i in range(k, len(li) - 1):
if li[i] > heap[0]:
heap[0] = li[i]
shit(heap, 0, k - 1)
# 3.挨个出数,使得列表倒序
for i in range(k - 1, -1, -1):
heap[0], heap[i] = heap[i], heap[0]
shit(heap, 0, i - 1)
return heap
时间复杂度:
O(klogn)
2、冒泡排序实现
1)解决思路
- 有序区在列表头,无序区在列表尾
- 遍历k(列表长度)趟列表
- 每走一趟从从无序区倒序依次取一个元素,与之前一个元素相比较,谁大谁往前走
- 每走一趟有序区增加一个元素,无序区减少一个元素
2)代码实现
@cal_time
def bubble_sort_topK(li, k):
for i in range(k):
for j in range(len(li) - 1, i, -1):
if li[j] > li[j - 1]:
li[j], li[j - 1] = li[j - 1], li[j]
return li[0:k]
时间复杂度:
O(kn)
3、对比执行时间
li = list(range(0, 100000))
random.shuffle(li)
li1 = copy.deepcopy(li)
li2 = copy.deepcopy(li)
heap_sort_topk(li1, 100)
bubble_sort_topK(li2, 100)
# 结果
heap_sort_topk执行时间:0.005194902420043945
bubble_sort_topK执行时间:0.9621851444244385