问题:
思路:
图解:
步骤1、将10个数,分为两组
和
步骤 2、对第一组进行堆排列
步骤3、将第二组数与第一组的堆排列的1进行比较,因0<1所以0被舍弃
步骤4、以此类推,7与1比较,因为7>1,所以7代替1,而1被舍弃,将7放入堆顶
步骤5、但是此时的堆并不是完备的,所以,进行完备操作,也就是把堆里最小的数放置在最顶部的位置上,如下:
步骤6、第二组剩下的2、4、5将继续重复步骤3、4、5直至第二组无数则停止
import time import random def cal_time(func): # 装饰器 ,用来检测算法所执行的时间 def wrapper(*args,**kwargs): t1=time.time() result=func(*args,**kwargs) t2=time.time() print("%s running time: %s secs." %(func.__name__,t2-t1)) return result return wrapper def sift(data,low,high): # 调整函数 i = low # 树的根 也就是父亲 ,这里只领导 j = 2 * i + 1 # 根的左孩子 也就是 儿子 ,这里指小领导 tmp = data[i] # 把根 取出来 做调整 , 在这里 领导 while j <= high: # high其实就是 根的右儿子(也就是最后一个儿子),如果 j= high 则表示没有右儿子,也就是说这里必须有儿子在 if j + 1< high and data[j] > data[j + 1]: # j + 1< high 代表有右儿子 , data[j] < data[j + 1] 说明左儿子比右儿子大 j += 1 # 这个 j 则变为右儿子 ,也就是 若有比 j 小的值,则 j 就变为比他小的那个值 if tmp > data[j]: # 如果领导能干 data[i] = data[j] # 则小领导上位 i = j # 小领导变为大领导 j = 2 * i + 1 # 小小领导变为小领导 else: # 如果领导能干 break # 那就待着吧 data[i] = tmp # 到最后 i 这里肯定会有空位 ,所以无论 tem 是谁 都要占住这个空位 def topn(li,n): # li为列表 k为个数 heap = li[0:n] # 存储的地方 # 建堆 for i in range(n // 2 - 1,-1,-1): sift(heap,i,n-1) # 遍历 for i in range(n,len(li)): if li[i] > heap[0]: # 如果这个数 > 堆顶 heap[0] = li[i] # 替代堆顶这个数 sift(heap,0,n-1) for i in range(n - 1, -1, -1): # n-1为high 也就是从堆得最后 一直到 0为止,也就是从刁民到领导 heap[0], heap[i] = heap[i], heap[0] # 堆的顶部 和 堆的末尾 互换, 也就是领导退休,刁民上位 sift(heap, 0, i - 1) # 0 代表着领导 ,i-1 代表着这个堆的位置不能把领导算在内了,也就是领导退休了,把他赶出这个城市了 return heap data = list(range(10000)) random.shuffle(data) print(topn(data,10))
结果显示为: