Was ist bei zwei Listen (nicht unbedingt sortiert) der effizienteste nicht rekursive Algorithmus, um den Schnittpunkt dieser Listen zu finden?
Was ist bei zwei Listen (nicht unbedingt sortiert) der effizienteste nicht rekursive Algorithmus, um den Schnittpunkt dieser Listen zu finden?
Antworten:
Sie können alle Elemente der ersten Liste in ein Hash-Set einfügen. Wiederholen Sie dann das zweite und überprüfen Sie für jedes seiner Elemente den Hash, um festzustellen, ob er in der ersten Liste vorhanden ist. Wenn ja, geben Sie es als Element der Kreuzung aus.
Vielleicht möchten Sie einen Blick auf Bloom-Filter werfen. Sie sind Bitvektoren, die eine probabilistische Antwort geben, ob ein Element Mitglied einer Menge ist. Die eingestellte Schnittmenge kann mit einer einfachen bitweisen UND-Verknüpfung implementiert werden. Wenn Sie eine große Anzahl von Null-Schnittpunkten haben, können Sie diese mithilfe des Bloom-Filters schnell entfernen. Sie müssen jedoch immer noch auf einen der anderen hier genannten Algorithmen zurückgreifen, um den tatsächlichen Schnittpunkt zu berechnen. http://en.wikipedia.org/wiki/Bloom_filter
Ohne Hashing haben Sie vermutlich zwei Möglichkeiten:
O(n + m)
aber nicht immer möglich.
O(n lg n) * 2 + O(n) * 2
die gleich ist wie O(n lg n)
.
Aus der Liste der eviews-Funktionen geht hervor, dass komplexe Zusammenführungen und Verknüpfungen unterstützt werden (wenn dies wie in der DB-Terminologie "Verknüpfung" ist, wird eine Schnittmenge berechnet). Stöbern Sie jetzt in Ihrer Dokumentation :-)
Zusätzlich hat eviews ein eigenes Benutzerforum - warum nicht dort fragen?
Erstellen Sie mit Satz 1 einen binären Suchbaum mit O(log n)
und iterieren Sie Satz 2 und suchen Sie die BST m X O(log n)
GesamtsummeO(log n) + O(m)+O(log n) ==> O(log n)(m+1)
In C ++ kann Folgendes mithilfe der STL-Map versucht werden
vector<int> set_intersection(vector<int> s1, vector<int> s2){
vector<int> ret;
map<int, bool> store;
for(int i=0; i < s1.size(); i++){
store[s1[i]] = true;
}
for(int i=0; i < s2.size(); i++){
if(store[s2[i]] == true) ret.push_back(s2[i]);
}
return ret;
}
Hier ist eine weitere mögliche Lösung, die ich mir ausgedacht habe, um O (nlogn) in zeitlicher Komplexität und ohne zusätzlichen Speicherplatz zu verwenden. Sie können es hier überprüfen https://gist.github.com/4455373
So funktioniert es: Angenommen, die Sätze enthalten keine Wiederholungen, führen Sie alle Sätze zu einem zusammen und sortieren Sie sie. Durchlaufen Sie dann die zusammengeführte Menge und erstellen Sie bei jeder Iteration eine Teilmenge zwischen dem aktuellen Index i und i + n, wobei n die Anzahl der im Universum verfügbaren Mengen ist. Was wir beim Schleifen suchen, ist eine sich wiederholende Folge der Größe n, die der Anzahl der Mengen im Universum entspricht.
Wenn diese Teilmenge bei i gleich dieser Teilmenge bei n ist, bedeutet dies, dass das Element bei i n-mal wiederholt wird, was der Gesamtzahl der Mengen entspricht. Und da es in keiner Menge Wiederholungen gibt, bedeutet dies, dass jede der Mengen diesen Wert enthält, also fügen wir ihn dem Schnittpunkt hinzu. Dann verschieben wir den Index um i +, was zwischen ihm und n verbleibt, da definitiv keiner dieser Indizes eine sich wiederholende Sequenz bilden wird.
Sortieren Sie zunächst beide Listen mit Quicksort: O (n * log (n). Vergleichen Sie dann die Listen, indem Sie zuerst die niedrigsten Werte durchsuchen und die allgemeinen Werte hinzufügen. Beispiel: in lua):
function findIntersection(l1, l2)
i, j = 1,1
intersect = {}
while i < #l1 and j < #l2 do
if l1[i] == l2[i] then
i, j = i + 1, j + 1
table.insert(intersect, l1[i])
else if l1[i] > l2[j] then
l1, l2 = l2, l1
i, j = j, i
else
i = i + 1
end
end
return intersect
end
Welches ist O(max(n, m))
wo n
und m
sind die Größen der Listen.
BEARBEITEN: Quicksort ist rekursiv, wie in den Kommentaren erwähnt, aber es sieht so aus, als gäbe es nicht rekursive Implementierungen
Die Verwendung von Sprungzeigern und SSE-Anweisungen kann die Effizienz von Listenkreuzungen verbessern.
Warum implementieren Sie nicht Ihre eigene einfache Hash-Tabelle oder Hash-Set? Es lohnt sich, keine Überschneidungen zu vermeiden, wenn Ihre Listen groß sind, wie Sie sagen.
Da Sie vorher ein wenig über Ihre Daten wissen, sollten Sie in der Lage sein, eine gute Hash-Funktion auszuwählen.
Wenn Sets (wie Sie sie im Titel nennen) als integriert unterstützt werden, gibt es normalerweise eine Schnittmethode.
Wie auch immer, wie jemand sagte, Sie könnten es leicht machen (ich werde keine Postleitzahl posten, jemand hat es bereits getan), wenn Sie die Listen sortiert haben. Wenn Sie keine Rekursion verwenden können, gibt es kein Problem. Es gibt schnell rekursionsfreie Implementierungen.
Ich habe ein paar gute Antworten aus diesen , dass Sie in der Lage sein können , anzuwenden. Ich habe noch keine Gelegenheit, sie auszuprobieren, aber da sie auch Kreuzungen abdecken, können Sie sie nützlich finden.
In PHP so etwas wie
function intersect($X) { // X is an array of arrays; returns intersection of all the arrays
$counts = Array(); $result = Array();
foreach ($X AS $x) {
foreach ($x AS $y) { $counts[$y]++; }
}
foreach ($counts AS $x => $count) {
if ($count == count($X)) { $result[] = $x; }
}
return $result;
}
Aus der Definition der Big-Oh-Notation:
T (N) = O (f (N)), wenn es positive Konstanten c und n 0 gibt, so dass T (N) ≤ cf (N) ist, wenn N ≥ n 0 ist.
Was in der Praxis bedeutet, dass, wenn die beiden Listen relativ klein sind, weniger als 100 Elemente in jeweils zwei for-Schleifen gut funktionieren. Durchlaufen Sie die erste Liste und suchen Sie in der zweiten nach einem ähnlichen Objekt. In meinem Fall funktioniert es einwandfrei, da ich nicht mehr als 10 - 20 maximale Elemente in meinen Listen habe. Eine gute Lösung ist jedoch, das erste O (n log n) zu sortieren, das zweite auch O (n log n) zu sortieren und sie zusammenzuführen Die beiden Listen sind gleich groß.