[英]A faster way to compare lists for a common element in Java?
我有一個用LinkedLists實現的圖形(用Vector實現),我想連接不共享任何公共元素的LinkedLists。 我認為我現在的操作方式需要O(n ^ 3)。 我有一個循環遍歷Vector的for循環,然后是一個嵌套的for循環遍歷Vector的for循環(以便可以將每個List與其他List進行比較),然后在該for循環中我使用遞歸來比較List。
在以這種方式嘗試之前,我嘗試在2nd for循環中使用while循環來遍歷每個列表,並使用二進制搜索來查看2nd列表是否包含每個元素,但是我認為這花費了相同的時間或更長的時間。 這是我的循環:
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);
}
}
假設我正確地閱讀了此內容,則可以用對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));
}
}
}
}
我可以嘗試反向索引, element -> [IDs of containing lists]
。 遍歷索引將告訴您哪些列表共享元素,因此無法連接。
list ID -> [IDs of incompatible lists]
如果存在用於加入兼容列表的特定規則,則步驟3可能會更加復雜,因為兼容性不是暫時的。
一些偽Java:為了我自己,我將假設數據結構看起來像這樣(可能我的Bin
是您的Row
,或多或少):
class Bin {
ID id;
LinkedList<Element> list;
}
箱的集合allBins
的類型為Collection<Bin>
。
步驟1:反向索引的類型為MultiValueMap<Element, ID>
。 也就是說,每個元素都映射到一組ID(包含該元素的容器的ID)。
MultiValueMap<Element, ID> reverseIndex;
for (Bin bin : allBins) {
for (Element e : bin) {
reverseIndex.put(e, bin.id);
}
}
步驟2:不兼容索引的類型為MultiValueMap<ID, ID>
,其中每個容器ID都映射到不兼容容器的容器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);
}
}
好的,最后一個比我計划的要詳細得多。
我意識到您正在尋找一種更快的方法來執行此操作,並且我認為@Michael Brewer-Davis提出了一種更好的方法來執行此操作,但是在創建列表之前是否可以解決該問題? 因此,與其在創建列表時進行比較,不如在創建列表時進行比較,這樣就不必殘酷地遞歸嗎? (我的意思可能是設計變更:僅比較不平等元素一次,以便將不相關的元素自然地組合在一起,並可能避免遞歸)
我實際上想到了一種比較列表的更快方法。 我列出了所有可能的元素,現在代替了元素列表,而是創建了一個long數組,long的每一位代表它們是否包含可能元素列表中的相應元素。 然后,我使用&運算符比較多頭,以了解它們是否具有任何共同的元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.