在Lucene中,如果用户的查询向量Term t = {xx,xx,……},BooleanQuery为AND时,每个t---->对应得到的倒排列表,倒排列表由许多的倒排索引项构成,然后取其中重复的文档编号,然后进行排序。器核心思想类似于如下问题:
现有两个数组:int []data1 = {12,45,65,2,5} int []data2 = {12,5,-8,9},取其中的交集。
实现的方案有很多,现在采取一种时间和空间相对较好的算法:集合压缩算法,即:1.分别计算两个数组的min和max(取值范围),加入到rangeList 中,然后计算rangeLis中重复的数值,加入到result(list)中;
2.计算rangeList的取值范围交集,比如[1,20,3,15],两个数组的取值范围交集为[3,15],放在数组中,然后根据这个交集分别去除两个数组中不在此范围内的数值,清空rangeList,清零数组;
3.重复上述步骤,直到符合终止条件位置。
以上是逻辑实现,最重要的还是数据结果,由于在这个过程中,会不断地去除数组中的数值,所以底层采用链式存储的线性表,性能会比较高。
今天下午试着写了这个算法,经过调试后,准确无误,现在上传代码,以供分享:
package com.txq.dataStructure;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedDeque;
/**
* 对两个数组取交集
* @author TongXueQiang
* @date 2016/05/12
*/
public class DataIntersection {
// 存储原始数据的链表
private Queue<Integer> data1 = new ConcurrentLinkedDeque<Integer>();
private Queue<Integer> data2 = new ConcurrentLinkedDeque<Integer>();
// 存放两个数据集取值范围的集合
private List<Integer> minAndMax = new ArrayList<Integer>();
// 存放两个取值范围的交集
private int[] intersection = new int[2];
// 存储两个数据集交集的结果集
private List<Integer> result = new ArrayList<Integer>();
public List<Integer> intersection(int[] originalData, int[] originalData1) {
// 1.数据备份
for (int i : originalData) {
data1.add(i);
}
for (int j : originalData1) {
data2.add(j);
}
while (true) {
// 2.计算两个集合的取值范围,加到minAndMax中
minAndMax.add(Collections.min(data1));
minAndMax.add(Collections.max(data1));
minAndMax.add(Collections.min(data2));
minAndMax.add(Collections.max(data2));
// 3.计算minAndMax中相同的数值,加入到result中,然后分别去除两个数据集中的这个相同的数值
int intersect;
int sum1 = sum(minAndMax);
Set<Integer> set = new HashSet<Integer>(minAndMax);
int sum2 = sum(set);
if (set.size() == 1) {// 如果set的size==1,直接输出结果
for (int i : set)
result.add(i);
return result;
} else if (minAndMax.size() - set.size() == 1) {
intersect = sum1 - sum2;
// 加入到result中
result.add(intersect);
// 对data1和data2分别去除intersection
data1.remove(intersect);
data2.remove(intersect);
} else if (set.size() == 2) {// set本身就是intersection
if (minAndMax.get(0) == minAndMax.get(1) && minAndMax.get(2) == minAndMax.get(3)) {
return null;
} else if (minAndMax.get(0) != minAndMax.get(1) && minAndMax.get(2) != minAndMax.get(3)) {
// 加入到result中
result.addAll(set);
// 对data1和data2分别去除intersection
for (int num : set) {
data1.remove(num);
data2.remove(num);
}
} else if (minAndMax.get(0) != minAndMax.get(1) || minAndMax.get(2) != minAndMax.get(3)) {
if (minAndMax.get(0) != minAndMax.get(1)) {
intersect = minAndMax.get(2);
// 加入到result中
result.add(intersect);
// 对data1和data2分别去除intersection
data1.remove(intersect);
data2.remove(intersect);
}
if (minAndMax.get(2) != minAndMax.get(3)) {
intersect = minAndMax.get(0);
// 加入到result中
result.add(intersect);
// 对data1和data2分别去除intersection
data1.remove(intersect);
data2.remove(intersect);
}
}
}
// 4.计算两个取值范围的交集,放入intersection数组中
intersection[0] = Math.max(minAndMax.get(0), minAndMax.get(2));
intersection[1] = Math.min(minAndMax.get(1), minAndMax.get(3));
// 5.分别去除不在intersection范围内的数值
removeNotInIntersection(data1);
removeNotInIntersection(data2);
// 终止条件
if (intersection[0] > intersection[1] || data1.size() == 0 || data2.size() == 0) {
break;
}
// 6.清空minAndMax,清零intersection
minAndMax.clear();
intersection = setIntersectToZero(intersection);
}
return result;
}
private int[] setIntersectToZero(int[] intersection) {
for (int i = 0; i < intersection.length; i++) {
intersection[i] = 0;
}
return intersection;
}
/**
* 分别去除不在intersection范围内的数值
*
* @param data
*/
private void removeNotInIntersection(Queue<Integer> data) {
if (data.size() == 0) {
return;
}
int min = Collections.min(data);
int max = Collections.max(data);
while (max > intersection[1] || min < intersection[0]) {
if (max > intersection[1])
data.remove(max);
if (min < intersection[0])
data.remove(min);
if (data.size() == 0) {
break;
}
min = Collections.min(data);
max = Collections.max(data);
}
}
/**
* 求和
*
* @param collection
* @return
*/
private Integer sum(Collection<Integer> collection) {
int sum = 0;
for (int i : collection) {
sum += i;
}
return sum;
}
}