Ich habe zwei große Mengen von ganzen Zahlen und B . Jeder Satz hat ungefähr eine Million Einträge, und jeder Eintrag ist eine positive ganze Zahl, die höchstens 10 Stellen lang ist.
Was ist der beste Algorithmus zur Berechnung von und B ∖ A ? Mit anderen Worten, wie kann ich die Liste der Einträge von A , die sich nicht in B befinden, effizient berechnen und umgekehrt? Was wäre die beste Datenstruktur, um diese beiden Mengen darzustellen und diese Operationen effizienter zu gestalten?
Der beste Ansatz ist, diese beiden Mengen als sortierte Listen zu speichern und jedes Element von linear mit jedem Element von B zu vergleichen . Können wir es besser machen?
algorithms
data-structures
sets
user917279
quelle
quelle
Antworten:
Wenn Sie bereit sind, die Mengen in einer spezialisierten Datenstruktur zu speichern, können Sie möglicherweise einige interessante Komplexitäten erhalten.
SeiI=O(min(|A|,|B|,|AΔB|))
Dann können Sie die Operationen und A Δ B jeweils in O ( I ⋅ log | A | + | B |) setzenA∪B,A∩B,A∖B AΔB O(I⋅log|A|+|B|I) erwartete Zeit. Sie erhalten also im Wesentlichen die minimale Größe der beiden Mengen oder die Größe der symmetrischen Differenz, je nachdem, welcher Wert geringer ist. Dies ist besser als linear, wenn der symmetrische Unterschied gering ist. dh wenn sie eine große Kreuzung haben. Tatsächlich ist dies für die beiden gewünschten Mengenunterschiedsoperationen praktisch ausgangssensitiv, da sie zusammen die Größe des symmetrischen Unterschieds ausmachen.
Siehe konfluent Persistent Sets und Karten von Olle Liljenzin (2013) für weitere Informationen.
quelle
Ein linearer Scan ist das Beste, was ich tun kann, wenn die Sätze als sortierte verknüpfte Listen dargestellt werden. Die Laufzeit ist .O(|A|+|B|)
Beachten Sie, dass Sie nicht jedes Element von paarweise mit jedem Element von B vergleichen müssen. Das würde zu einer Laufzeit von O ( | A | × | B | ) führenA B O(|A|×|B|) , was viel schlimmer ist. Um die symmetrische Differenz dieser beiden Mengen zu berechnen, können Sie stattdessen eine Technik verwenden, die der "Zusammenführungs" -Operation in mergesort ähnelt und die so geändert wurde, dass Werte weggelassen werden, die beiden Mengen gemeinsam sind.
Im Einzelnen können Sie einen rekursiven Algorithmus wie den folgenden erstellen , um zu berechnen , vorausgesetzt, A und B werden als verknüpfte Listen mit ihren Werten in sortierter Reihenfolge dargestellt:A∖B A B
Ich habe dies in Pseudo-Python dargestellt. Wenn Sie Python nicht lesen,
A[0]
ist es der Kopf der verknüpften ListeA
,A[1:]
der Rest der Liste und+
die Verkettung von Listen. Wenn Sie in Python arbeiten, möchten Sie es aus Effizienzgründen wahrscheinlich nicht genau so implementieren, wie oben beschrieben. Beispielsweise ist es möglicherweise besser, Generatoren zu verwenden, um das Erstellen vieler temporärer Listen zu vermeiden, aber ich wollte zeigen Ihnen die Ideen in möglichst einfacher Form. Der Zweck dieses Pseudocodes besteht nur darin, den Algorithmus zu veranschaulichen, und keine konkrete Implementierung vorzuschlagen.Ich denke nicht, dass es besser geht, wenn Ihre Sets als sortierte Listen dargestellt werden und Sie möchten, dass die Ausgabe als sortierte Liste erfolgt. Man muss sich grundsätzlich jedes Element von und B ansehen . Informelle Rechtfertigungsskizze: Wenn es ein Element gibt, das Sie nicht angesehen haben, können Sie es nicht ausgeben. Daher können Sie nur dann auf die Betrachtung eines Elements verzichten, wenn Sie wissen, dass es sowohl in A als auch in B vorhanden ist. Aber woher wissen Sie, dass es vorhanden ist, wenn Sie seinen Wert nicht untersucht haben?A B A B
quelle
Wenn A und B gleich groß, disjunkt und verschachtelt sind (z. B. ungerade Zahlen in A und gerade Zahlen in B), ist der paarweise Vergleich von Elementen in linearer Zeit wahrscheinlich optimal.
Wenn A und B Blöcke von Elementen enthalten, die sich genau in A oder B oder in beiden befinden, ist es möglich, die Differenz, Vereinigung und Schnittmenge in sublinearer Zeit zu berechnen. Wenn sich beispielsweise A und B in genau einem Element unterscheiden, kann die Differenz in O (log n) berechnet werden.
http://arxiv.org/abs/1301.3388
quelle
Eine Möglichkeit ist die Verwendung von Bitvektoren zur Darstellung der Mengen (wobei dien Die dritte Position stellt das Vorhandensein oder Fehlen eines Elements dar. Die Operationen vom Typ "Set" reduzieren sich dann auf Binäroperationen, die auf Digitalcomputern schnell (und mit mehreren Bits gleichzeitig) ausgeführt werden können. in diesem FallA - B = a ∧ b¯¯ wo a , b sind die Bitvektoren. Die relative Effizienz dieser Technik gegenüber anderen Techniken hängt auch von der Sparsamkeit ab. Für dichtere Mengen kann es effizienter sein als andere Ansätze. Natürlich ist auch die gesamte Operation peinlich parallel, sodass festgelegte Operationen parallel ausgeführt werden können.
quelle
long
kann 32 Elemente oder 1byte
, 8 Elemente speichern . 1M Einträge können also nur in ~ 125K RAM gespeichert werden! Der Speicher kann erheblich effizienter sein als andere Darstellungen, je nachdem, wie das Problem implementiert ist ...