python实现堆排序及topk问题

堆排序

​
# 思路
'''
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值