zoukankan      html  css  js  c++  java
  • golang 堆排序(TopK)

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

  • 相关阅读:
    gvim : invalid input string
    端口
    Sequence Overview
    vi的使用
    Ubuntu安装CodeBlocks相关问题总结
    中断
    Ubuntu Software Repository
    UVA 12299 RMQ with Shifts
    UVA 12293 Box Game
    POJ 3468 A Simple Problem with Integers (1)
  • 原文地址:https://www.cnblogs.com/9527s/p/13672170.html
Copyright © 2011-2022 走看看