java解决topk问题

面试题中经常用到堆,这里总结一下。

方法一:对源数据中所有数据进行排序,取出前K个数据,就是TopK。

但是当数据量很大时,只需要k个最大的数,整体排序很耗时,效率不高。

方法二:维护一个K长度的数组a[],先读取源数据中的前K个放入数组,对该数组进行升序排序,再依次读取源数据第K个以后的数据,和数组中最小的元素(a[0])比较,如果小于a[0]直接pass,大于的话,就丢弃最小的元素a[0],利用二分法找到其位置,然后该位置前的数组元素整体向前移位,直到源数据读取结束。

这比方法一效率会有很大的提高,但是当K的值较大的时候,长度为K的数据整体移位,也是非常耗时的。

 

对于这种问题,效率比较高的解决方法是使用最小堆


首先建立堆


   
   
   
   
  1. public class Heap {
  2. private int[] data;
  3. public Heap(int[] data){
  4. this.data=data;
  5. buildHeap();
  6. }
  7. public void buildHeap() {
  8. for ( int i = data.length/ 2- 1; i>= 0; i--) {
  9. heapity(i);
  10. }
  11. }
  12. public void heapity(int i) {
  13. int left=getLeft(i);
  14. int right=getRight(i);
  15. int smallIndex=i;
  16. if(left
  17. smallIndex=left;
  18. if(right
  19. smallIndex=right;
  20. if(smallIndex==i)
  21. return;
  22. swap(i, smallIndex);
  23. heapity(smallIndex);
  24. }
  25. public int getLeft(int i){
  26. return ((i+ 1)<< 1)- 1;
  27. }
  28. public int getRight(int i){
  29. return (i+ 1)<< 1;
  30. }
  31. public void swap(int i,int j){
  32. data[i]^=data[j];
  33. data[j]^=data[i];
  34. data[i]^=data[j];
  35. }
  36. public int getMin(){
  37. return data[ 0];
  38. }
  39. public void setMin(int i){
  40. data[ 0]=i;
  41. heapity( 0);
  42. }
  43. }
测试


   
   
   
   
  1. public class TopK {
  2. private static int[] topK( int[] data, int k){
  3. int topk[]= new int[k];
  4. for ( int i = 0; i < k; i++) {
  5. topk[i]=data[i];
  6. }
  7. Heap heap= new Heap(topk);
  8. for ( int j = k; j < data.length; j++) {
  9. int min=heap.getMin();
  10. if(data[j]>min)
  11. heap.setMin(data[j]);
  12. }
  13. return topk;
  14. }
  15. public static void main(String[] args) {
  16. int[] data = { 33, 86, 59, 46, 84, 76, 1236, 963};
  17. int[] topk=topK(data, 3);
  18. for ( int i : topk) {
  19. System.out.print(i+ ",");
  20. }
  21. }
  22. }



你可能感兴趣的:(数据结构和算法,topk)