从海量数据中寻找出topK的最优算法代码

package findMinNumIncludedTopN;
/**
 * 小顶堆
 * @author TongXueQiang
 * @date 2016/03/09
 * @since JDK 1.8
 */
public class MinHeap {
 int[] heap;
 int heapsize;

 public MinHeap(int[] array) {
  this.heap = array;
  this.heapsize = heap.length;
 }
 
 /**
  * 构建小顶堆
  */
 public void BuildMinHeap() {
  for (int i = heapsize / 2 - 1; i >= 0; i--) {
   Minify(i);// 依次向上将当前子树最大堆化
  }
 }
 
 /**
  * 堆排序
  */
 public void HeapSort() {
  for (int i = 0; i < heap.length; i++) {
   // 执行n次,将每个当前最大的值放到堆末尾
   swap(heap,0,heapsize-1);   
   heapsize--;
   Minify(0);
  }
 }
 
 /**
  * 对非叶节点调整
  * @param i
  */
 public void Minify(int i) {
  int l = 2*i + 1;
  int r = 2*i + 2;
  int min;

  if (l < heapsize && heap[l] < heap[i])
   min = l;
  else
   min = i;
  if (r < heapsize && heap[r] < heap[min])
   min = r;
  if (min == i || min >= heapsize)// 如果largest等于i说明i是最大元素
            // largest超出heap范围说明不存在比i节点大的子女
   return;
  swap(heap,i,min);
  Minify(min); 
 }

 private void swap(int[] heap, int i, int min) {
  int tmp = heap[i];// 交换i与largest对应的元素位置,在largest位置递归调用maxify
  heap[i] = heap[min];
  heap[min] = tmp;  
 }

 public void IncreaseValue(int i, int val) {
  heap[i] = val;
  if (i >= heapsize || i <= 0 || heap[i] >= val)
   return;
  int p = Parent(i);
  if (heap[p] >= val)
   return;
  heap[i] = heap[p];
  IncreaseValue(p, val);
 }

 private int Parent(int i) {
  return (i - 1) / 2;
 }
}

 

package findMinNumIncludedTopN;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/**
 * 从海量数据中查找出前k个最大值,精确时间复杂度为:k + (n - k) * lgk,空间复杂度为 O(k),目前为所有算法中最优算法
 *
 * @author TongXueQiang
 * @date 2016/03/08
 * @since JDK 1.8
 */
public class FindMinNumIncluedTopN {
 /**
  * 从海量数据中查找出前k个最大值
  *
  * @param k
  * @return
  * @throws IOException
  */
 public int[] findMinNumIncluedTopN(int k) throws IOException {
  Long start = System.nanoTime();
  
  int[] array = new int[k];
  int index = 0;
  // 从文件导入海量数据
  BufferedReader reader = new BufferedReader(new FileReader(new File("F:/number.txt")));
  String text = null;
  // 先读出前n条数据,构建堆
  do {
   text = reader.readLine();
   if (text != null) {
    array[index++] = Integer.parseInt(text);
   }   
  } while (text != null && index <= k - 1);
  
  MinHeap heap = new MinHeap(array);//初始化堆
  for (int i : heap.heap) {
   System.out.print(i + " ");
  }
  
  heap.BuildMinHeap();//构建小顶堆
  System.out.println();
  System.out.println("构建小顶堆之后:");
  for (int i : heap.heap) {
   System.out.print(i + " ");
  }
  System.out.println();
  // 遍历文件中剩余的n(文件数据容量,假设为无限大)-k条数据,如果读到的数据比heap[0]大,就替换之,同时更新堆
  while (text != null) {
   text = reader.readLine();
   if (text != null && !"".equals(text.trim())) {
    if (Integer.parseInt(text) > heap.heap[0]) {
     heap.heap[0] = Integer.parseInt(text);
     heap.Minify(0);//调整小顶堆
    }
   }
  }
  //最后对堆进行排序(默认降序)
  heap.HeapSort();
  
  Long end = System.nanoTime();
  double time = (end - start) / Math.pow(10,9);
  System.out.println("用时:"+ time + "秒");
  for (int i : heap.heap) {
   System.out.println(i);
  }
  return heap.heap;
 }
}

posted @ 2016-12-12 18:07  佟学强  阅读(1494)  评论(0编辑  收藏  举报