堆排序可以很好解決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然后合並排序。