簡體   English   中英

Java合並O(1)中的2個集合

[英]Java merge 2 collections in O(1)

我需要能夠將2個大型集合合並到1.我可以使用哪種集合類型? 我不需要隨機訪問各個元素。 通常我會選擇一個鏈表,但是我不能將Java中的2個鏈表與O(1)的運行時合並,這可以在許多其他語言中完成,因為我必須將每個元素復制到新的列表中。

編輯:謝謝你的所有答案。 你的答案都非常有用,我設法完成了工作。 下次我將使用自己的鏈接列表實現開始。

您可以使用GuavaIterables.concat方法之一在O(1)中創建連接的Iterable視圖:

Iterable<T> combined = Iterables.concat(list1, list2);

這將允許您將兩個列表的所有元素作為一個對象進行迭代,而無需復制任何元素。

這里最簡單的解決方案是列表清單。 意味着您需要一些簡單的包裝函數,但並不復雜。

理論上,您可以在O(1)中合並2個鏈接列表,因為您所要做的就是將第一個節點指向第二個節點(假設您有這些參考)。

addAll集合方法似乎意味着O(n)的運行時間,因為它們正在討論迭代器。 細節可能是特定於JVM的......

我不認為有任何集合將在O(n)中組合。 你可能不得不自己動手。

我認為你最好的方法是創建一個List的實現,它以List>作為參數,然后委托。 換句話說,有一個列表列表,並將它們連接起來作為一個列表。 當您瀏覽列表1的元素時,您將開始查看列表2。

出於某種原因,我認為番石榴有這樣的清單。 但我無法在他們的javadocs中找到它。

如果您只想擁有對象集合並在O(1)時間內合並它們,並且不介意實現自己的數據結構,那么最簡單的方法是使用不平衡的二叉樹:每個節點都是一個leaf(存儲值)或兩個樹的組合,您可以將它們實現為具有抽象超類或接口的兩個類。 深度優先遍歷可用於提取元素。

這與ColinD關於迭代器連接的建議基本相同,但更多的是基礎。

問題是迭代這個集合 不會是O( n )! 它將是O( n + m ),其中 m是您執行的合並數(因為每個是要遍歷的節點)。 我的解決方案和ColinD都是如此。 我不知道這個問題的所有可能解決方案是否屬實。

別介意以上。 在這種方案下,每個合並至少添加一個元素,因此m < n ,因此迭代成本仍為O( n )。 (如果你使用迭代器連接,請確保你不經常連接空迭代器,因為這會增加成本。)

合並鏈表確實是O(1),您可以采用相同的方式考慮基於數組的列表,即在其間鏈接多個Object []。

有上面的實現,從中/開始刪除/插入時比ArrayList快。 迭代幾乎是一樣的。 隨機訪問可能稍微慢一點。

我想從apache.commons推薦CompositeCollection類,但是看看它在O(n)中運行的源代碼 如果您只需要迭代元素並且不想按照ColinD的建議使用Google Collections,您可以輕松創建自己的復合迭代器,例如

public class CompositeCollectionIterator<T> implements Iterator<T>{

  private Iterator<T>[] iterators;
  private int currentIteratorIndex = 0;
  public CompositeCollectionIterator( Collection<T>... aCollections ) {
    iterators = new Iterator[ aCollections.length];
    for ( int i = 0, aCollectionsLength = aCollections.length; i < aCollectionsLength; i++ ) {
      Collection<T> collection = aCollections[ i ];
      iterators[i] = collection.iterator();
    }
  }

  public boolean hasNext() {
    if ( iterators[currentIteratorIndex].hasNext() ) return true;
    else if ( currentIteratorIndex < iterators.length - 1 ){
      currentIteratorIndex++;
      return hasNext();
    }
    return false;
  }

  public T next() {
    return iterators[currentIteratorIndex].next();
  }

  public void remove() {
    iterators[currentIteratorIndex].remove();
  }
}

通過使用兩個鏈接列表作為集合,並存儲指向每個列表的第一個最后一個元素的指針(在添加/刪除項目時可能需要更新兩個指針),您可以在O(1)中合並兩個列表 - 只需連接第一個列表的最后一個元素到第二個列表的第一個元素,並相應地調整第一個/最后一個指針。

我擔心您需要在Java中滾動自己的鏈接列表實現,因為您無法直接訪問LinkedList的基礎節點,因此您無法將第一個列表的最后一個元素連接到第二個列表的第一個元素。

幸運的是,在Java中很容易找到鏈表實現,因為它是數據結構課程中非常常見的主題。 例如, 這里有一個 - 我知道,名稱是西班牙語,但ListaEncadenada (“LinkedList”)和NodoLista (“ListNode”)中的代碼非常簡單,應該是不言自明的,最重要的是 - 實現包含指向列表的第一個和最后一個元素的指針,可以輕松修改以滿足您的需要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM