Java merge 2 collections in O(1)

Muszę być w stanie połączyć 2 duże zbiory w 1. Jakiego typu kolekcji mogę użyć najlepiej? Nie potrzebuję przypadkowego dostępu do poszczególnych elementów. Zwykle wybrałbym linkedlist, jednak nie mogę połączyć 2 linkedlist w Javie z runtime O(1), co można zrobić w wielu innych językach, ponieważ będę musiał skopiować każdy element do nowej listy.

Edit: dziękuję za wszystkie odpowiedzi. Wasze odpowiedzi były bardzo pomocne i udało mi się wykonać zadanie. Następnym razem użyję moja własna implementacja linked list na początek.

Author: Tiddo, 2011-12-03

8 answers

Możesz utworzyć skonkatenowany Iterable widok W O(1) używając jednego z Iterabli Guava 'S .metody concat :

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

Pozwoli to na iterację wszystkich elementów obu list jako jednego obiektu bez kopiowania żadnych elementów.

 57
Author: ColinD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 14:45:28

Najprostszym rozwiązaniem jest tutaj lista list. Oznacza to, że potrzebujesz prostych funkcji owijania, ale nic skomplikowanego.

 12
Author: Voo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 14:01:57

W teorii, możesz połączyć 2 połączone listy W O(1), Ponieważ wszystko, co musisz zrobić, to skierować ostatni węzeł pierwszego do pierwszego węzła drugiego (zakładając, że masz te odniesienia).

Metoda zbioru addAll wydaje się sugerować czas działania O(n), ponieważ mówią o iteratorach. Szczegóły mogą być specyficzne dla JVM...

Myślę, że nie ma żadnych zbiorów, które połączyłyby się w O (n). Może sam będziesz musiał to zrobić.

 10
Author: hvgotcodes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 14:05:08

Myślę, że najlepiej byłoby stworzyć implementację listy, która jako swoje argumenty przyjmuje List>, a następnie deleguje. Innymi słowy, mieć listę list i połączyć je, aby działać jako jedna lista. Kiedy przechodzisz obok elementów listy 1, zaczynasz patrzeć na listę 2.

Z jakiegoś powodu myślałem, że guava ma taką listę. Ale nie mogę znaleźć tego w ich Javadoc.

 3
Author: yshavit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 14:07:59

Jeślipo prostu Chcesz mieć kolekcje obiektów i scalać je w czasie O(1) i nie masz nic przeciwko implementacji własnej struktury danych, najprostszym sposobem na to jest użycie niezrównoważonego drzewa binarnego: każdy węzeł jest albo liściem (przechowującym wartość), albo kombinacją dwóch drzew i możesz zaimplementować je jako dwie klasy z abstrakcyjną klasą nadrzędną lub interfejsem. Do ekstrakcji pierwiastków można użyć trawersu o pierwszej głębokości.

Jest to zasadniczo to samo, co ColinD sugestia konkatenacji iteratora, ale więcej gołych kości.

haczyk polega na tym, że iteracja nad tą kolekcją będzie , a nie być O(n)! Będzie O (n + m) Gdzie m jest liczbą wykonanych połączeń (ponieważ każdy z nich jest węzłem do przejścia). Jest to prawda zarówno mojego rozwiązania, jak i Colinda. Nie wiem, czy to prawda dla wszystkich możliwych rozwiązań tego problemu.

Mniejsza o powyższe. W ramach tego programu każdy merge dodaje co najmniej jeden element, więc m n i tak koszt iteracji jest nadal O (n). (Jeśli używasz konkatenacji iteratora, upewnij się, że często nie łączysz pustych iteratorów, ponieważ zwiększyłoby to koszt.)

 2
Author: Kevin Reid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-04 01:29:56

Scalanie połączonych list jest rzeczywiście O(1) i można traktować listy oparte na tablicach w ten sam sposób, tzn. mając wiele obiektów połączonych między sobą.

Istnieją implementacje powyższego, jest to szybsze niż ArrayList podczas usuwania / wstawiania od środka / startu. I iteracja jest praktycznie taka sama. Losowy dostęp może być jednak nieco wolniejszy.

 1
Author: bestsss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 14:14:01

Chciałem zasugerować klasę CompositeCollection z apache.commons, ale patrząc na kod źródłowy to działa również w O (n). Jeśli potrzebujesz tylko iterować nad elementami i nie chcesz korzystać z kolekcji Google zgodnie z sugestią Colinda, możesz łatwo utworzyć własny iterator kompozytowy, np.

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();
  }
}
 1
Author: Robin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 14:36:07

Używając dwóch połączonych list jako kolekcji i przechowując wskaźniki do pierwszego i ostatniego elementu każdej listy(oba wskaźniki potencjalnie wymagają aktualizacji podczas dodawania/usuwania elementów), możesz połączyć obie listy W O (1) - po prostu podłącz ostatni element pierwszej listy do pierwszego elementu drugiej listy i odpowiednio dostosuj pierwszy/ostatni wskaźnik.

Obawiam się, że będziesz musiał zwijać własną implementację linkowanych list w Javie, ponieważ nie masz bezpośredni dostęp do bazowych węzłów LinkedList, dlatego nie można połączyć ostatniego elementu pierwszej listy z pierwszym elementem drugiej listy.

Na szczęście łatwo jest znaleźć implementacje linked list w Javie, ponieważ jest to bardzo popularny temat w kursach struktury danych. Na przykład tutaj jest jeden - wiem, nazwy są w języku hiszpańskim, ale kod w ListaEncadenada ("LinkedList") i NodoLista ("ListNode") jest dość prosty i powinien być oczywisty, a co najważniejsze - implementacja zawiera wskaźniki do pierwszego i ostatniego elementu listy i może być łatwo modyfikowana do własnych potrzeb.

 0
Author: Óscar López,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-04 01:45:55