现有一亿个数据,要求从其中找出最小的一万个数,希望所需的时间和空间最小,也就是所谓的topK问题
TopK问题就是从海量的数据中取最大(或最小的)的K个数。
TopK问题其实是有线性时间复杂度的解的,在这里不作赘述
我使用的是堆排序方案,即维护一个大小为k的最小堆,遍历剩余的所有数据,并依次和堆顶元素比较,若其大于堆顶元素,则将其与堆顶元素互换,最终得到的堆即使所求。
java代码:
/** * TopK算法,从一个数组中挑出最大的k个元素,如果第k个元素存在相等的,则只取靠前的 * @param data 数据源,其元素必须实现Comparable接口 * @param k * @return 长度为k的一个数组,储存的是符合条件的元素在data中的下标位置 */ public static <T extends Comparable<T>> int[] topK(T[] data,int k){ if (k>=data.length){ int[] temp=new int[data.length]; for(int i=0;i<data.length;i++) temp[i]=i; return temp; } Heap<Ele<T>> heap=new MinHeapImpl<Ele<T>>(); for(int i=0;i<k;i++){ heap.add(new Ele<T>(data[i], i)); } for(int i=k;i<data.length;i++){ if (data[i].compareTo(heap.element().t)>0){ heap.remove(); heap.add(new Ele<T>(data[i],i)); } } int[] temp=new int[k]; int i=0; for(Ele<T> ele:heap){ temp[i]=ele.index; i++; } return temp; }
节点类:
class Ele<T extends Comparable<T>> implements Comparable<Ele<T>>{ T t; int index; /* (非 Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(Ele<T> o) { // TODO 自动生成的方法存根 return t.compareTo(o.t); } public Ele(T t,int index){ this.t=t; this.index=index; } }
关于堆的构建在我的另一片随笔里有提到