Różnica między zestawami obliczeniowymi między dwoma dużymi zestawami


14

Mam dwóch dużych zestawów liczb całkowitych i B . Każdy zestaw ma około miliona wpisów, a każdy wpis jest dodatnią liczbą całkowitą o długości co najwyżej 10 cyfr. AB

Jaki jest najlepszy algorytm do obliczania i B A ? Innymi słowy, jak mogę skutecznie obliczyć listę pozycji A , które nie są w B i odwrotnie? Jaka byłaby najlepsza struktura danych reprezentująca te dwa zestawy, aby te operacje były wydajne?ABBAAB

Najlepszym podejściem, jakie mogę wymyślić, jest przechowywanie tych dwóch zestawów jako posortowanych list i porównywanie każdego elementu z każdym elementem B w sposób liniowy. Czy możemy zrobić lepiej?AB


Jeśli chcesz go przechowywać w inny sposób, możesz uzyskać lepsze wyniki.
Realz Slaw

Ponadto, jeśli chcesz uzyskać wyniki jako domyślną strukturę danych; możesz po prostu stworzyć taką strukturę, która będzie wysyłać zapytania do dwóch zestawów, aby odpowiedzieć na każde z nich.
Realz Slaw

1
@ user917279 Jedna ważna kwestia: zazwyczaj można wymieniać między sobą czas przetwarzania wstępnego / budowy, czas zapytania i wykorzystanie pamięci. Czy rzadko edytujesz strukturę, ale często pytasz? Odwrotnie? Czy pamięć jest problemem, czy nie? Na takie pytania można odpowiedzieć z praktycznego punktu widzenia i poinformować o wyborze „właściwej” „teoretycznej” konstrukcji.
Raphael

1
@Raphael Czy sugerujesz, że można zrobić lepiej niż zbiegające się zestawy (pod względem złożoności), wykorzystując więcej pamięci i / lub poświęcając więcej czasu na przygotowanie. Jestem ciekawy, czy uważasz, że to możliwe. Nie widzę tabel wyszukiwania jako opcji dla zestawów danych wejściowych tego rozmiaru.
smossen

1
@ user917279 Jeśli weźmiesz pod uwagę przykład dwóch ogromnych zestawów, które są identyczne, to każda struktura danych utworzona przy użyciu obliczania wartości skrótu obsługiwałaby testowanie równości w O (1), ponieważ równe struktury zostaną scalone podczas tworzenia, a zatem będą miały tę samą lokalizację pamięci. Zbieżnie trwałe zestawy wykorzystują haszowanie także wtedy, gdy dwie struktury są prawie równe. Złożoność jest najlepsza, jaką do tej pory widziałem dla zestawów uporządkowanych.
smossen

Odpowiedzi:


9

Jeśli chcesz przechowywać zestawy w specjalnej strukturze danych, możesz uzyskać ciekawe komplikacje.

Niech I=O(min(|A|,|B|,|AΔB|))

Następnie możesz ustawić operacje i A Δ B , każda w O ( I log | A | + | B |AB,AB,ABAΔBoczekiwany czas. Zasadniczo otrzymujesz minimalny rozmiar dwóch zestawów lub rozmiar różnicy symetrycznej, w zależności od tego, która jest mniejsza. Jest to lepsze niż liniowe, jeśli różnica symetryczna jest niewielka; to znaczy. jeśli mają duże skrzyżowanie. W rzeczywistości dla dwóch żądanych operacji ustawiania różnicy jest to praktycznie zależne od wyników, ponieważ razem stanowią one wielkość różnicy symetrycznej.O(Ilog|A|+|B|I)

Aby uzyskać więcej informacji, zobacz Zestawy i mapy o trwałej spójności autorstwa Olle Liljenzin (2013).


Pułapki w papierze to uporządkowane drzewa wyszukiwania. Nie liczyłbym ich jako nieposortowane struktury danych.
smossen

@smossen to prawda, zredagowałem to.
Realz Slaw

6

Skan liniowy jest najlepszym, co wiem, jak to zrobić, jeśli zestawy są reprezentowane jako posortowane listy połączone. Czas działania to .O(|A|+|B|)

Zauważ, że nie musisz porównywać każdego elementu z każdym elementem B , parami. Prowadziłoby to do czasu wykonania O ( | A | × | B | ) , co jest znacznie gorsze. Zamiast tego, aby obliczyć różnicę symetryczną tych dwóch zestawów, można użyć techniki podobnej do operacji „scalania” w trybie scalania, odpowiednio zmodyfikowanej w celu pominięcia wartości wspólnych dla obu zestawów.ABO(|A|×|B|)

Bardziej szczegółowo, możesz zbudować algorytm rekurencyjny, taki jak poniżej, aby obliczyć , zakładając, że A i B są reprezentowane jako listy połączone z ich wartościami w uporządkowanej kolejności:ABAB

difference(A, B):
    if len(B)=0:
        return A # return the leftover list
    if len(A)=0:
        return B # return the leftover list
    if A[0] < B[0]:
        return [A[0]] + difference(A[1:], B)
    elsif A[0] = B[0]:
        return difference(A[1:], B[1:])  # omit the common element
    else:
        return [B[0]] + difference(A, B[1:])

Reprezentowałem to w pseudo-Pythonie. Jeśli nie czytasz Pythona, A[0]jest on głową połączonej listy A, A[1:]jest resztą listy i +reprezentuje konkatenację list. Ze względu na wydajność, jeśli pracujesz w Pythonie, prawdopodobnie nie chciałbyś go wdrożyć dokładnie tak, jak powyżej - na przykład lepiej byłoby użyć generatorów, aby uniknąć tworzenia wielu list tymczasowych - ale chciałem pokażę Ci pomysły w najprostszej możliwej formie. Celem tego pseudokodu jest jedynie zilustrowanie algorytmu, a nie zaproponowanie konkretnej implementacji.

Nie sądzę, aby można było zrobić coś lepszego, jeśli twoje zbiory są reprezentowane jako listy posortowane i chcesz, aby dane wyjściowe były dostarczane jako lista posortowana. Ci zasadniczo trzeba patrzeć na każdy element i B . Nieformalny szkic uzasadnienia: jeśli istnieje jakikolwiek element, którego nie obejrzałeś, nie możesz go wydrukować, więc jedynym przypadkiem, w którym możesz pominąć patrzenie na element, jest to, że wiesz, że jest on obecny zarówno w A, jak i B , ale skąd możesz wiedzieć, że jest obecny, jeśli nie spojrzałeś na jego wartość?ABAB


fantastycznie, czy mamy inne opcje, jeśli zostanie usunięte ograniczenie, że zestawy mają być przechowywane podczas sortowania list?
user917279,

2

Jeśli A i B są równej wielkości, rozłączne i przeplatane (np. Liczby nieparzyste w A i liczby parzyste w B), to porównanie par elementów w czasie liniowym jest prawdopodobnie optymalne.

Jeśli A i B zawierają bloki elementów, które znajdują się dokładnie w jednym z A lub B, lub w obu, można obliczyć ustawioną różnicę, sumę i przecięcie w czasie subliniowym. Na przykład, jeśli A i B różnią się dokładnie jednym przedmiotem, różnicę można obliczyć w O (log n).

http://arxiv.org/abs/1301.3388


1
Mówi, że zestawy są uporządkowane, co może oznaczać, że są przechowywane jako listy, drzewa wyszukiwania lub coś innego. Jeśli dane muszą być przechowywane w postaci list, nie jest interesujące proszenie o „najlepszy algorytm do obliczania AB”, gdy żaden algorytm nie byłby lepszy niż skanowanie list w czasie liniowym (dla którego już znalazł algorytm).
smossen

1
Boże, połączyłeś ten sam artykuł co ja (raczej ja, tak samo jak ty) ... nazwij swoje linki następnym razem: D
Realz Slaw

@smossen fantastyczny, zgodnie z moją wiedzą (?), którą reprezentowałem, jako posortowane listy, ale z pokorą przyjmę także inne sugestie.
user917279,

2

nABab¯a,b


Z 1010możliwe wpisy, wektory bitowe wcale nie są praktyczne.
Raphael

1
R., nie trafia w sedno. jeden longmoże pomieścić 32 elementy lub 1 byte, 8 elementów. więc wpisy 1M mogą być przechowywane tylko w ~ 125K pamięci RAM! pamięć może być znacznie wydajniejsza niż inne reprezentacje, w zależności od sposobu zaimplementowania problemu ...
vzn

Potrzebowałbyś więc ponad 12 MB na zestawy, którymi zainteresowany jest OP. To wysadza wszystkie pamięci podręczne (obecnie) i będzie okropne dla rzadkich zestawów. W szczególności utworzenie pustego zestawu dominuje we wszystkich innych operacjach (w przypadku zestawów rzadkich). Nawiasem mówiąc, Knuth rozwiązuje ten problem w TAoCP.
Raphael

12 MB? co? plakat powiedział, że ma tylko 2 zestawy. plakat nie określał rzadkości / gęstości jego zestawu. zaznaczono to w mojej odpowiedzi. zakładasz, że ma rzadkie zbiory? nie ma jednej poprawnej odpowiedzi, podejście to wskazano jako alternatywną opcję, która może być użyteczna w zależności od okoliczności. nie jest to rzadko używane w tym kontekście ...
dniu

Sugeruję ponowne przeczytanie pytania: „Każdy zestaw zawiera około miliona wpisów, a każdy wpis jest dodatnią liczbą całkowitą o długości co najwyżej 10 cyfr”. Tam są1010 różne liczby, które mogą wystąpić, i są o 106te na liście. Oznacza to, że tylko 0,01% wszystkich wpisów w wektorze bitowym to 1 - naprawdę nazwałbym to bardzo rzadkim. (Okazało się, że moje 12 MB było za niskie; oczywiście trzeba1010b1.15solb.)
Raphael
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.