python实现堆排序及topk问题

本文介绍了堆排序的基本原理,包括如何构造堆和实现topk问题的解决方案。通过递归构建堆和调整堆顶元素,实现在O(nlogn)时间内完成排序并找出列表中最大的k个数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆排序

​
# 思路
'''
1.构造堆
2.挨个出数(每次选出一个最大(小)的数)

时间复杂度:nlogn

'''


# 构造堆
def sift(li, low, high):
    '''
    :param li:列表
    :param low:堆的根节点
    :param high:堆的最后一个叶子节点
    :return:
    '''

    i = low  # i最开始指向根节点
    j = 2 * i + 1  # j一开始指向i的左孩子
    tmp = li[low]  # 堆顶元素

    while j <= high:  # 只要j不越界

        # j指向i的子节点中更大的一个节点
        if j + 1 <= high and li[j + 1] > li[j]:  # 如果右孩子存在且比左孩子大,那么j就指向右孩子
            j = j + 1

        # 现在判断应该把i放在哪个地方
        if li[j] > tmp:
            li[i] = li[j]
            # 更新i和j的位置
            i = j
            j = 2 * i + 1
        else:
            li[i] = tmp
            break
    else:
        li[i] = tmp  # 如果是因为j越界结束的循环,tmp应该放在i的位置


@clocked
def heap_sort(li):
    # 构造堆
    n = len(li)
    # 从最后一个含有叶子节点的节点开始构造

    '''
    由父节点推子节点:   父:n ---> 左孩子:2n+1  右孩子:2n+2
    由子节点推父节点:   左孩子/右孩子:n  父:(n-1)//2
    
    '''

    # 依次构造堆
    for i in range((n - 1 - 1) // 2, -1, -1):
        # i表示需要构建的部分的堆的根节点
        sift(li, i, n - 1)

    # 一个一个出
    for i in range(n - 1, -1, -1):
        li[0], li[i] = li[i], li[0]
        sift(li, 0, i - 1)

​

topk问题

#思路
'''
1.首先选列表的前k个数建堆
2.从列表的第k+1个数开始遍历列表
    如果当前元素大于堆顶元素,就和堆顶元素进行交换
3.挨个出数得到排序好的topk
'''
# 构造堆
def sift(li, low, high):
    '''
    :param li:列表
    :param low:堆的根节点
    :param high:堆的最后一个叶子节点
    :return:
    '''

    i = low  # i最开始指向根节点
    j = 2 * i + 1  # j一开始指向i的左孩子
    tmp = li[low]  # 堆顶元素

    while j <= high:  # 只要j不越界

        # j指向i的子节点中更大的一个节点
        if j + 1 <= high and li[j + 1] < li[j]:  # 如果右孩子存在且比左孩子大,那么j就指向右孩子
            j = j + 1

        # 现在判断应该把i放在哪个地方
        if li[j] < tmp:
            li[i] = li[j]
            # 更新i和j的位置
            i = j
            j = 2 * i + 1
        else:
            li[i] = tmp
            break
    else:
        li[i] = tmp  # 如果是因为j越界结束的循环,tmp应该放在i的位置

@clocked
def topk(li, k):
    heap = li[:k]

    # 建堆
    for i in range((k - 2) // 2, -1, -1):
        sift(heap, i, k - 1)

    # 遍历
    for i in range(k, len(li) - 1):
        if li[i] > heap[0]:
            heap[0] = li[i]
            sift(heap, 0, k - 1)

    # 出数
    for i in range(k - 1, -1, -1):
        heap[0], heap[i] = heap[i], heap[0]
        sift(heap, 0, i - 1)

    return heap

### 使用堆排序实现TopK算法 #### 堆的概念及其应用 堆是一种特殊的完全二叉树,其中每个父节点的键值总是大于等于(大顶堆)或小于等于(小顶堆)其子节点的键值。这种特性使得堆非常适合用于解决TopK问题,在这类问题中需要快速获取集合中的前K个最大或者最小元素。 对于TopK问题而言,当目标是从大量数据中筛选出最大的K项时,应采用小顶堆;反之,则需构建大顶堆。这是因为当我们维持一个小顶堆并保持堆大小不超过K的情况下,堆顶始终代表当前已处理过的所有元素里第K大的那个数[^4]。 #### 实现思路 为了有效地运用堆来求解TopK问题,可以遵循如下策略: - 初始化一个容量为K的小顶堆; - 遍历输入序列中的每一个元素: - 如果当前遍历到的新元素比堆顶还大,则替换掉堆顶,并重新调整堆结构以满足性质; - 若新元素不大于堆顶,则跳过此元素继续下一个循环迭代。 最终得到的就是原列表里的前K个较大数值组成的有序队列。 以下是基于上述逻辑的具体Python代码示例: ```python import heapq def top_k_largest(nums, k): min_heap = [] for num in nums: if len(min_heap) < k or num > min_heap[0]: if len(min_heap) == k: heapq.heappop(min_heap) heapq.heappush(min_heap, num) return sorted([item for item in reversed([heapq.heappop(min_heap) for _ in range(len(min_heap))])], reverse=True) if __name__ == "__main__": test_data = [10, 7, 9, 8, 1, 5] result = top_k_largest(test_data, 3) print(result) ``` 这段程序展示了如何利用`heapq`库提供的功能轻松创建和操作堆对象,从而完成对给定整型数组`test_data`内的三个最高分数进行提取的任务[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值