python 堆排序--topk实现

现在又n个数,设计算法得到前k大的数 (k

解决思路

  1. 排序后切片O(nlogn)
  2. 排序LowB三人组 O(kn) k取100个
  3. 堆排序思路 O(nlogk) k 是27

1

  • 取列表前k个元素建立一个小根堆。堆顶就是目前第k大的数

  • 依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素;如果大于堆顶,则将堆顶更换为该元素,并且 对堆进行一次调整

  • 遍历列表所有元素后,倒序弹出堆顶

    在这里插入图片描述
    python 堆排序--topk实现_第1张图片
    1在堆里面最小的

小的放弃 ,大的替换在比较

要是7,7就把1替换掉,3和7替换,3上去,7下来了
python 堆排序--topk实现_第2张图片

python 堆排序--topk实现_第3张图片

4、5都别3大,替换掉
python 堆排序--topk实现_第4张图片

    #li 列表
    # low: 堆的根节点位置 第一个元素
    # higth 堆的指向最后一个元素的位置
    # return
    #i->指当前一层 和下一个层
    #i 是市长
    #i要是大于higth 退出了
    #n-1 就是是整个堆元素最后一个下标


def sift(li,low,hight):
    i = low
    #找孩子 左孩子
    j = 2 * i +1
    tmp = li[low] #把堆顶存起来
    while  j <= hight: #只要j位置有数
        #右孩子要右,右孩子比较大 并且右孩子大于左孩子     右孩子不越界 j+1 <=hight 
        if j+1 <=hight  and li[j+1] < li[j]:
        #j 指向右孩子  这个指的是两个孩子更大的数
            j = j + 1
        if li[j] < tmp:  #目前要是,tmp大就放过去,还是j大放上面去
            li[i] = li[j]
            i = j       #可以交换了    现在j等于新的i     i等于原来的j
            j = 2 * i + 1
        else :  #tmp 更大,把tmp放到i的位置上  假如堆点是6
            li[i] = tmp  # 6放到原来8break
    else: #就是2没法和别的比了,就放到该去的地方去
        li[i] = tmp  #把tmp放到叶子节点上去

#最后非叶子节点
#n的最后一个下标是n-1,找他的父亲就孩子,(n-1-1)/2
#孩子下标是 n
#孩子找父亲 (n-1)/2 里面的n的最后一个下标是n-1 所有(n-1-1)/2 -> (n-2)/2

def topk(li,k):
        heap = li[0:k]
        for i in range((k-2)//2,-1,-1):
                sift(heap,i,k-1)

        #1.建堆
        for i in range(k,len(li)-1):
                if li[i] > heap[0]:
                        heap[0] = li[i]
                        sift(heap,0,k-1)
        #print(heap)

        #2. 遍历
        for i in range(k-1,-1,-1):
                heap[0], heap[i] = heap[i], heap[0]
                sift(heap,0,i -1)
        return heap

import random
li = list(range(1000))
random.shuffle(li)

print(topk(li,10))

在这里插入图片描述

你可能感兴趣的:(算法)