python-排序算法(四)、堆排序之topk问题

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值