Wie kann ich zwei Sätze von 1000 Zahlen miteinander vergleichen?

Lesezeit: 2 Minuten

Benutzer-Avatar
backen

Ich muss ungefähr 1000 Nummern mit 1000 anderen Nummern vergleichen.

Ich habe beide geladen und serverseitig verglichen:

foreach( $numbers1 as $n1 ) {
  foreach( $numbers2 as $n2 ) {
    if( $n1 == $n2 ) {
      doBla();
    }
  }
}

Das hat lange gedauert, also habe ich versucht, den gleichen Vergleich clientseitig mit zwei versteckten durchzuführen
div Elemente. Dann verglichen sie mit JavaScript. Es dauert immer noch 45 Sekunden, um die Seite zu laden (unter Verwendung von hidden div Elemente).

Ich brauche nicht die Nummern zu laden, die nicht gleich sind.

Gibt es einen schnelleren Algorithmus? Ich denke daran, sie datenbankseitig zu vergleichen und einfach die Fehlernummern zu laden und dann einen Ajax-Aufruf für die verbleibenden Nicht-Fehlernummern durchzuführen. Aber ist eine MySQL-Datenbank schnell genug?

  • Bitte sehen Sie sich meine Antwort an. Ich bezweifle, dass die Optimierung des Suchalgorithmus die richtige Antwort ist.

    – markmnl

    19. Januar 2011 um 14:01 Uhr

Benutzer-Avatar
Spitz

Sortieren Sie zuerst die Listen. Dann können Sie beide Listen von Anfang an durchgehen und dabei vergleichen.

Die Schleife würde in etwa so aussehen:

var A = getFirstArray().sort(), B = getSecondArray().sort();

var i = 0, j = 0;
while (i < A.length && j < B.length) {
    if (A[i] === B[j]) {
        doBla(A[i]);
        i++; j++;
    }
    else if (A[i] < B[j]) {
        i++;
    }
    else
        j++;
}

(Das ist JavaScript; Sie könnten es auch serverseitig machen, aber ich kenne kein PHP.)

Bearbeiten – nur um allen Hashtable-Fans (die ich natürlich respektiere) fair zu sein, es ist ziemlich einfach, das in JavaScript zu tun:

var map = {};
for (var i = 0; i < B.length; ++i) map[B[i]] = true; // Assume integers.
for (var i = 0; i < A.length; ++i) if (map[A[i]]) doBla(A[i]);

Oder wenn die Zahlen Gleitkommazahlen sind oder sein könnten:

var map = {};
for (var i = 0; i < B.length; ++i) map['' + B[i]] = true; // Assume integers.
for (var i = 0; i < A.length; ++i) if (map['' + A[i]]) doBla(A[i]);

Da Zahlen ziemlich billig zu hashen sind (sogar in JavaScript ist die Konvertierung in Strings vor dem Hashen überraschend billig), wäre dies ziemlich schnell.

  • Wenn dies nicht der Fall ist, dann … Wenn A die Größe n und B die Größe m hat, dauert es nlg(n)+mlg(m)+min(m,n) Zeit, während der Ansatz des OP nur mn ist. ..

    – letzte Ursache

    15. Oktober 2010 um 14:52 Uhr

  • Wenn m und n beide groß sind – wie in der Frage angegeben -, dann werden die Sorten absolut, definitiv schneller sein. Rechne nach! Das Sortieren eines Arrays mit 1000 Elementen entspricht etwa 3000 Operationen, also 3000+3000+1000. Aber 1000 * 1000 ist 100 mal so viel Arbeit.

    – Spitze

    15. Oktober 2010 um 14:59 Uhr

  • Ja, aber für zwei Arrays der Größe 1000 sind das 1000 * lg (1000) + 1000 * lg (1000) + 1000, was ~ 2000 * 10 + 1000, was ~ 21000 ist. Die Methode des OP, mDie n-Zeit ist 1000^2, was 1000000 ist. 21000 << 1000000. Deshalb ist die asymptotische Auswertung wichtig - n^2 = o(nlg(n)), nlg(n) = O(mn) , was bedeutet, dass die Methode von Pointy um einiges schneller ist, da lg(n) << n

    – Fastmonolith

    15. Oktober 2010 um 15:02 Uhr

  • Dieser Code reproduziert nicht, was der Code von OP tut. Wenn x erschien x1 mal und x2 Zeiten in Liste 1 bzw. 2, doBla() laufen soll x1 * x2 Mal, was hier nicht der Fall ist.

    – Kache

    15. Oktober 2010 um 15:50 Uhr

  • @Kache4 das wäre eine ziemlich einfache Änderung – ich überlasse es dem Leser als Übung 🙂

    – Spitze

    15. Oktober 2010 um 16:15 Uhr

Benutzer-Avatar
Phil Pafford

  • beide wären jedoch bestenfalls O(n.log n).

    – Dhruvvogel

    15. Oktober 2010 um 17:13 Uhr

  • @dhruvbird Frage gestellt ‘Ich muss ungefähr 1000 Nummern mit 1000 anderen Nummern vergleichen.’ die obige PHP-Funktion tut wie gefragt. Die zurückgegebene Ausgabe sollte das gewünschte Ergebnis sein, bei dem der Benutzer leicht manipulieren kann, um von seinem doBla() zu profitieren.

    – Phil Pafford

    15. Oktober 2010 um 18:33 Uhr

  • “allerdings wären beide bestenfalls O(n.log n)” theoretisch wahr, aber das Aufrufen einer Hashtable-Suche O(log n) wird dem nicht wirklich gerecht. In der Praxis verhält es sich eher wie O(1)

    – CodesInChaos

    15. Oktober 2010 um 21:32 Uhr

  • @dhruvbird, O (n log n) ist das Beste, was Sie für dieses Problem tun können.

    – Luqui

    16. Oktober 2010 um 11:09 Uhr

  • @phill: Aber der OPs-Code kann möglicherweise n ^ 2-Zahlen drucken, was impliziert, dass die Komplexität NICHT geringer als O (n ^ 2) sein kann.

    – Dhruvvogel

    21. Oktober 2010 um 20:46 Uhr

Benutzer-Avatar
Preet-Sangha

In Bezug auf die Datenbank kann dies ein Join von 1000 Zeilen mit weiteren 1000 Zeilen sein. Damit kann jedes moderne Datenbanksystem umgehen.

select x from table1
inner join table2
on table1.x = table2.y

wo table1 und table2 sind die betroffenen Zeilen und könnten dieselbe Tabelle sein.

  • +1, wie Preet sagt, seien Sie vorsichtig, dass es sich um eine moderne DB handelt, sagen wir … nach 1974: P

    – Unvernunft

    15. Oktober 2010 um 13:40 Uhr

  • Ich würde gerne wissen, wie die Codasyl-DBs damit umgegangen wären.

    – Preet-Sangha

    15. Oktober 2010 um 13:43 Uhr

  • Ich bin mir nicht sicher, warum angenommen wird, dass die Elemente für diese Arrays aus einer Datenbank stammen. Liegt es daran, dass er ein Beispiel in PHP und Javascript vorgeführt hat? Die Quelle kann wirklich alles sein.

    – Srdjan Pejic

    15. Oktober 2010 um 18:18 Uhr


  • Ja, und die Lösung kann wirklich alles sein, da sie auch mit SQL gekennzeichnet war.

    – Haylem

    15. Oktober 2010 um 18:41 Uhr

  • Dieser Wille völlig das Problem beim Laden von Seiten mindern, da die Datenbank dies sicherlich viel schneller tun wird als der Javascript-Interpreter, selbst wenn dies ineffizient wäre.

    – Stefan Kendall

    15. Oktober 2010 um 19:51 Uhr

Benutzer-Avatar
markmnl

Was Sie haben, sollte nicht so lange dauern – was macht doBla()? Ich vermute, das dauert die Zeit? Der Vergleich von zwei Sätzen von 1000000 Zahlen mit demselben Algorithmus dauert im Handumdrehen.

Das ist urkomisch – die Anzahl der Optimierungstechniken als Antworten – das Problem ist nicht Ihr Algorithmus – was auch immer doBla() tut, nimmt die Zeit um ein Vielfaches länger in Anspruch, als jede Optimierung Ihnen helfen würde 🙂 esp. da die Sets nur 1000 lang sind und man sie erst sortieren muss..

Vielleicht schneiden Sie einfach die Array-Werte, um Zahlen zu finden, die in beiden Arrays vorhanden sind?

$result = array_intersect($numbers1, $numbers2);
foreach ($result as $val)
  doBla();

Wenn Sie zuerst Liste2 sortieren und dann eine binäre Suche nach jeder Zahl in Liste1 durchführen, werden Sie eine enorme Geschwindigkeitssteigerung feststellen.

Ich bin nicht ein PHP-Typ, aber das sollte Sie auf die Idee bringen:

sort($numbers2);

foreach($numbers1 as $n1)
{
   if (BinarySearch($numbers2, $n1) >= 0) {
     doBla();
 }
}

Da ich kein PHP-Typ bin, kenne ich die Bibliothek nicht, aber ich bin sicher, dass das Sortieren und die binäre Suche einfach genug zu finden sein sollten.

Notiz: Falls Sie mit einer binären Suche nicht vertraut sind; Sie sortieren Liste2, weil binäre Suchen mit sortierten Listen arbeiten müssen.

Benutzer-Avatar
JRL

Sortieren Sie sie zuerst.

1019810cookie-checkWie kann ich zwei Sätze von 1000 Zahlen miteinander vergleichen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy