最小堆求topk个数

最小堆求topk个数

堆是一个完全二叉树,第i个节点的左子节点编号为2i+1,右子节点编号2i+2
最小堆性质:root->data < root->left->data && root->data < root->right->data
建堆->调整->排序+调整->取前k个数
调整:从第len/2-1个节点开始,len为数组长度,倒数第一个非叶子结点,依次从右往左,从底至上调整堆,满足最小堆性质.
[4,5,1,6,2,7,3,8]
在这里插入图片描述
1.为什么用最小堆?
最小堆满足根<左 且根<右的性质,树节点的值随层数增加是递增的。维护一个大小为k的堆,树中共有k个结点,其中堆顶也就是根结点的值是最小的。
当数组中的值大于堆顶元素时,用该值替换堆顶,并调整堆,使其满足最小堆的性质。排序结束时,堆中的k个元素就是最大的k个数

假设现在有7个数[2,5,4,3,1,6,7],要求前top k, k = 3, 先构建一棵大小为k的堆,求解过程如下图,如果当前数 > 堆顶元素,则替换之,调整堆, 所有的元素遍历完后,最后的堆就是要求的 top k
在这里插入图片描述
2.如何处理原数组中有重复元素的情况?
替换堆顶只有当 当前排序的元素大于堆顶才会替换,否则舍弃该元素。
也可以事先对数组进行去重处理
Java:

import java.util.*;

public class topK {
    public static int  findK(ArrayList<Integer> arr,int k){
        ArrayList<Integer> heap = new ArrayList<>();
        for(int i=0;i<k;i++){
            heap.add(arr.get(i));
        }
        createHeap(heap,k);
        for(int i=k;i<arr.size();i++){
            if(heap.get(0)<arr.get(i)){  //根结点值最小,替换根结点的值
                heap.set(0,arr.get(i));
                heapRify(heap,0,k);
            }
        }
        return heap.get(0);
    }
    public static void createHeap(ArrayList<Integer>arr,int k){
        for(int i=k/2-1;i>=0;i--){
            heapRify(arr,i,k);
        }
    }
    public static void heapRify(ArrayList<Integer> arr,int i,int len){
        int left = 2*i+1;
        int right = 2*i+2;
        int largest = i;
        if(left<len && arr.get(largest)>arr.get(left)){ //建立的是小根堆,根结点值最小,树的层数越深,值越大
            largest = left;
        }
        if(right<len && arr.get(largest)>arr.get(right)){
            largest = right;
        }
        if(largest != i){
            int tmp = arr.get(largest);
            arr.set(largest,arr.get(i));
            arr.set(i,tmp);
            heapRify(arr,largest,len);
        }
    }

    public static void quicksort(ArrayList<Integer> arr, int left,int right){
        if(left>=right){
            return;
        }
        int povit = arr.get(left);
        int i=left,j=right;
        while(i<j){
            while(i<j&&arr.get(j)>=povit){
                j--;
            }
            while(i<j&&arr.get(i)<=povit){
                i++;
            }
            if(i!=j){
                int tmp = arr.get(i);
                arr.set(i,arr.get(j));
                arr.set(j,tmp);
            }
        }
        arr.set(left,arr.get(i));
        arr.set(i,povit);
        quicksort(arr,left,i-1);
        quicksort(arr,i+1,right);
    }

    public static void main(String[] args) {
        //输入格式[3,1,2,2,5,4],2

        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        int k = line.charAt(line.length()-1) - '0';
        ArrayList<Integer> arr = new ArrayList<>();

        for(int i=0;i<line.length()-3;i++){
            char ch = line.charAt(i);
            if(ch==','||ch=='['){
                continue;
            }
            int num = ch-'0';
            if(! arr.contains(num)){
                arr.add(num);
            }
        }
        int res = findK(arr,k);
        quicksort(arr,0,arr.size()-1);
        System.out.println(arr.get(arr.size()-k));
        System.out.println(res);
    }
}

C++

#include<vector>
#include<iostream>
using namespace std;

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        if(input.size()==0 || k==0){
            return vector<int>();
        }
        if(k>input.size()){
            return vector<int>();
        }
        createHeap(input);
        int len  = input.size();
        for(int i=0;i<input.size();i++){
              int last = input[len-1];
              input[len-1] = input[0];
              input[0] = last;
              len -= 1;
              heapRify(input,0,len);
        }        
        
        return vector<int>(input.begin(),input.begin()+k);
    }
    
    void heapRify(vector<int> &input,int i,int len){
        int left = 2*i+1;
        int right = 2*i+2;
        int largest = i;
        
        if(left<len && input[left]>input[largest]){
            largest  = left;
        }
        if(right<len && input[right]>input[largest]){
            largest = right;
        }
        if(largest !=i){
            int tmp = input[largest];
            input[largest] = input[i];
            input[i] = tmp;
            heapRify(input,largest,len);
        }        
    }
    void createHeap(vector<int> &input){
        int len = input.size();
        for(int i=len/2-1;i>=0;i--){
            heapRify(input,i,len);
        }
    }
    
};

int main(){

	int k = 4;
	Solution s;
	
	vector<int> nums = {4,5,1,6,2,7,3,8};

	vector<int> v = s.GetLeastNumbers_Solution(nums,k);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值