【前言】在大规模数据处理中,常遇到的一类问题是,在海量数据中找出出现频率最高的前K个数,或者从海量数据中找出最大的前K个数,这类问题通常称为“topK”问题
【解决思路】
针对topK类问题,通常比较好的方案是【分治+trie树/hash+小顶堆】,即先将数据集按照hash算法分解成多个小数据集,然后使用trie树或者hash表统计每个小数据集中的query词频,之后用小顶堆求出每个数据集中出频率最高的前K个数,最后在所有top K中求出最终的top K。
实际上,最优的解决方案应该是最符合实际设计需求的方案,在实际应用中,可能有足够大的内存,那么直接将数据扔到内存中一次性处理即可,也可能机器有多个核,这样可以采用多线程处理整个数据集。
【 解决】在得到数据后,如何对获得的数据进行topK排序呢。下面简单介绍几种常见方法。【1】基于Partition(分区)解决TopK min的问题:根据数组的第K个数字来调整,使得比第K个数小的都在数组的左边,比第K个数据大的所有数字在数组的右边。
/**
* 最小的K个数,O(N)解法,需要修改原数组
* @param a
* @param n
* @param b
* @param k
*/
public void TopKmin(int[] a,int n,int[] b,int k){
if(a==null||k>n||n<=0||k<=0)
return;
int left=0;
int right=n-1;
int index=Partition(a,left,right);
while(index!=k-1){
if(index>k-1)
index=Partition(a, left, index-1);
else
index=Partition(a, index+1, right);
}
for(int i=0;i=pivot)
right--;
if(left
复杂度分析:先用Hash表统计每个Query出现的次数,O(N);然后第二步、采用堆数据结构找出Top 10,N*O(logK)。所以,我们最终的时间复杂度是:O(N) + *O(N1*logK)。(N为数据总数,N1为不重元素个数)。
@Test
public void testBuildMINHeap(){
int[] a={49,38,65,97,76,13,49,78,34,12,64};
int k=3;
int[] topK=new int[k];
for(int i=0;iroot){
topK[0]=a[i];
//buildMinHeap(topK, k);
heapfiy(topK, 0, k);
}
}
//buildMinHeap(a,a.length);
System.out.println(Arrays.toString(topK));
}
public void heapfiy(int[] a,int i,int len){
//int len=a.length;
int left=2*i+1;
int right=2*i+2;
int smallest=i;
while(true){
if(left=0;i--){
heapfiy(a, i,len);
}
}
/*
队尾
|1 |3
|2 |2
|3 |1
队头
降序 升序
*/
public static int[] topKLargest(int[] input, int k) {//降序
PriorityQueue minheap = new PriorityQueue(k, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
if(o1 < o2) {
return 1;
} else if(o1 > o2) {
return -1;
} else {
return 0;
}
}
});
for (int i : input) {
minheap.add(i);
}
int[] out = new int[k];
for (int i = 0; i < out.length; i++) {
out[i] = minheap.poll();
}
return out;
}
public static int[] topKSmallest(int[] input, int k) {//升序
PriorityQueue minheap = new PriorityQueue(k, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
if(o1 < o2) {
return -1;
} else if(o1 > o2) {
return 1;
} else {
return 0;
}
}
});
for (int i : input) {
minheap.add(i);
}
int[] out = new int[k];
for (int i = 0; i < out.length; i++) {
out[i] = minheap.poll();
}
return out;
}
public static void main(String[] args) {
int[] out = topKLargest(new int[] { 10, 23, 5, 1, 7, 8, 4, 5, 7, 12,
523 }, 3);
System.out.print("Largest: ");
for (int o : out) {
System.out.print(o + " ");
}
out = topKSmallest(new int[] { 10, 23, 5, 1, 7, 8, 4, 5, 7, 12,
523 }, 3);
System.out.println();
System.out.print("Largest: ");
for (int o : out) {
System.out.print(o + " ");
}
}
《十道海量数据处理面试题与十个方法大总结》:http://blog.csdn.net/v_JULY_v/archive/2011/03/26/6279498.aspx