堆排序可以很好解决TopK问题
时间复杂度 N(logN),不稳定排序,相同大小数据仍可能交换位置
寻找海量数据中最大的100个数据,可以建立容量100的小顶堆,然后将后面的数据与堆顶最小值比较,
如果比它大,进行交换重新将堆进行调整,后面数据以此类推,可以得到top 100的数据
package main import "fmt" //想得到从小到大的排序结果,需要构建大顶堆,然后将堆顶最大值与最后的数据交换, //依次进行,可以得到顺序的结果 func HeapSort(nums []int) { N:=len(nums)-1 //从底部到顶部构建大顶堆,最后一个非叶子节点开始 for i:=N/2-1;i>=0;i--{ //减少1才是最后一个非叶子节点。 sink(nums,i,N) } //将堆顶值和末尾交换,重新调整堆 for i:=N;i>=0;i--{ wap(nums,0,i) sink(nums,0,i-1)//交换之后,数组最后一位不算在堆内,需要减1操作 } //不同写法,结果一样 /*for N>=0{ wap(nums,0,N) N-- sink(nums,0,N) }*/ } func sink(nums []int,k,N int) { for{ i:=2*k+1 if i>N{ break } //找左右子节点最大值 if i+1<=N&&nums[i+1]>nums[i]{ i++ } //已经大于最大值,不需要再交换 if nums[k]>=nums[i]{ break } wap(nums,k,i) k = i //继续向上调整 } } func wap(nums []int,x,y int){ nums[x],nums[y] = nums[y],nums[x] } func main() { s := []int{-1,9, 0, 6, 5, 8, 2, 1, 7, 4, 3} fmt.Println(s) HeapSort(s) fmt.Println(s) }
TopK问题,一亿数据找最大10000
建立10000的最小堆,数据依次放入堆,比堆顶大则互换下沉,建堆O(nlogn) 总时间复杂 O(mnlogn) m=一亿 n=10000
下面简单例子
//TopK问题 //维护小顶堆,比最小的大,放头部下沉,最终得到topK
func sink(array []int,start,length int) { for{ //2*n+1 可以画图就知道为什么了,是左边子节点
next:=2*start+1
if next>length{ break } if next+1<=length&&array[next+1]<array[next]{ next++ } //上层小于下面,不用互换了
if array[start]<=array[next]{ break } //互换继续下沉
array[start],array[next] = array[next],array[start] start = next } } func main() { array:=[]int{2,1,5,8,5,6,3,2,7} //tok 5
res:=make([]int,5) for _,v:=range array{ if v<=array[0]{ continue } res[0] = v sink(res,0,4) } fmt.Println(res) }
还可以分别放在1000个文件分别找到前10000然后合并排序。