比较Java中常见元素列表的更快方法?

时间:2010-11-16 17:53:30

标签: java algorithm

我有一个LinkedLists的图形(用Vector实现),我想连接不共享任何公共元素的LinkedLists。我认为我现在这样做的方式需要O(n ^ 3)。我有一个迭代遍历Vector的for循环,然后是一个嵌套的for循环遍历Vector(这样我可以将每个List与其他每个List进行比较),然后在for循环中我使用递归来比较列表。

在尝试这种方式之前,我尝试在第二个for循环内部使用while循环迭代每个列表并使用二进制搜索来查看第二个列表是否包含每个元素,但我认为这需要相同的时间或更长时间。 这是我的循环:

 public void addEdges(){
  for(int i =0; i < size()-1; i++){
   for(int j = i+1; j < size(); j++){
    if(compatible(get(i),get(j),1,1)){
     get(i).linkTo(get(j));
     get(j).linkTo(get(i));
    }
   }
  }
 }

这是我的递归:

 public boolean compatible(Row a, Row b, int indexA, int indexB){
  if(a.get(indexA).getEnd() == b.get(indexB).getEnd()){
   return false;
  }
  else if(a.get(indexA).getEnd() == 0){
   return true;
  }
  else if(a.get(indexA).getEnd() > b.get(indexB).getEnd()){
   return compatible(a,b,indexA+1,indexB);
  }
  else{
   return compatible(b,a,indexB+1,indexA);
  }
 }

4 个答案:

答案 0 :(得分:1)

假设我正确阅读此内容,您可以通过调用Collections.disjoint静态方法替换compatible方法。

编辑:代码示例:

public void addEdges(){
  for(int i =0; i < size()-1; i++){
   for(int j = i+1; j < size(); j++){
    if(Collections.disjoint(get(i),get(j))){
     get(i).linkTo(get(j));
     get(j).linkTo(get(i));
    }
   }
  }
 }

答案 1 :(得分:0)

我可能会尝试反向索引element -> [IDs of containing lists]。迭代索引将告诉您哪些列表共享元素,因此无法连接。

  • 第1步:创建反向索引
  • 第2步:创建不兼容索引list ID -> [IDs of incompatible lists]
  • 步骤3:迭代不兼容性地图以加入兼容的列表。

如果存在加入兼容列表的特定规则,则步骤3可能会更复杂,因为兼容性不是暂时的。


一些伪Java:为了我自己,我假设数据结构看起来像这样(可能我的Bin是你的Row,或多或少):

class Bin {
    ID id;
    LinkedList<Element> list;
}

一组箱子allBins的类型为Collection<Bin>

步骤1:反向索引的类型为MultiValueMap<Element, ID>。也就是说,每个元素都映射到一组ID(包含该元素的bin)。

MultiValueMap<Element, ID> reverseIndex;

for (Bin bin : allBins) {
    for (Element e : bin) {
        reverseIndex.put(e, bin.id);
    }
}

步骤2:不兼容性索引的类型为MultiValueMap<ID, ID>,其中每个bin ID都映射到不兼容的bin的bin ID集。

MultiValueMap<ID, ID> incompatibilityIndex;

for (Element e : reverseIndex.keySet()) {
    List<ID> binsWithE = reverseIndex.get(e);
    for (ID id : binsWithE) {
        incompatibilityIndex.putAll(id, binsWithE); // each bin is incompat with itself
    }
}

步骤3:现在我们可以加入任何两个不在彼此不兼容地图中的垃圾箱。由于连接两个箱会改变不兼容性,我们必须更加棘手:

Set<Bin> binsRemainingToProcess; // == original allBins
Set<Bin> binsProcessed; // == new allBins

while (binsRemainingToProcess.size() > 0) {
    Bin bin = // grab any bin to work on from binsRemainingToProcess

    // grab any compatible bins
    // could iterate until we find one, but I'm going to compute all compatible
    List<ID> compatibleBinIDs = // all bin IDs in binsRemaining...
    List<ID> incompatibleBinIDs = incompatibilityIndex.get(bin.id);
    compatibleBinIDs.removeAll(incompatibleBinIDs);

    if (compatibleBinIDs.size() > 0) {
        Bin otherBin = // some bin with ID in compatibleBinIDs

        // joining the two bins -- means joining the inner lists,
        // but also joining the incompatibilities
        joinDataStructures(bin, otherBin);
        incompatibilityIndex.putAll(bin.id, incompatibilityIndex.get(otherBinID));

        // we don't need the other bin anymore, but we may be able to join
        // the first bin to others
        binsRemainingToProcess.remove(otherBin);
    } else {
        // couldn't join with anyone; we're done with this bin and can move on
        binsRemainingToProcess.remove(bin);
        binsProcessed.add(bin);
    }
}

好的,所以最后一个结果比我计划的要详细得多......

答案 2 :(得分:0)

我意识到你正在寻找更快的方法来做到这一点,我想@Michael Brewer-Davis 提出了一种更好的方法,但有一种方法可以在创建之前解决问题 清单?因此,在创建列表时,不是比较列表,而是在创建列表时进行比较,这样您就不必如此粗暴地进行递归了? (我的意思可能是设计上的改变:只比较一次不等式的元素,以便不相关的元素自然地组合在一起并可能避免递归)

答案 3 :(得分:0)

我实际上想到了一种更快速的方式来比较我的列表。我列出了所有可能的元素,现在而不是元素列表,我创建了一个long数组,long的每个位表示它们是否包含可能元素列表中的相应元素。然后我用&amp;运算符来比较多头以查看它们是否有任何共同元素。