Gegeben sind zwei sortierte Arrays a , b vom Typ T mit der Größe n und m . Ich suche nach einem Algorithmus, der die zwei Reihen in eine neue Reihe (der maximalen Größe n + m) zusammenführt.
Wenn Sie eine billige Vergleichsoperation haben, ist dies ziemlich einfach. Nehmen Sie einfach vom Array mit dem niedrigsten ersten Element, bis eines oder beide Arrays vollständig durchlaufen sind, und fügen Sie dann die verbleibenden Elemente hinzu. In etwa so /programming/5958169/how-to-merge-two-sorted-arrays-into-a-sorted-array
Die Situation ändert sich jedoch, wenn zwei Elemente verglichen werden. Dies ist wesentlich teurer als das Kopieren eines Elements vom Quell-Array in das Ziel-Array . Zum Beispiel könnten Sie ein Array von großen Ganzzahlen mit beliebiger Genauigkeit oder Strings haben, bei denen ein Vergleich ziemlich teuer sein kann. Nehmen Sie einfach an, dass das Erstellen von Arrays und das Kopieren von Elementen kostenlos ist und dass nur der Vergleich von Elementen kostet.
In diesem Fall möchten Sie die beiden Arrays mit einer minimalen Anzahl von Elementvergleichen zusammenführen . Hier sind einige Beispiele, bei denen Sie weitaus bessere Ergebnisse erzielen sollten als mit dem einfachen Zusammenführungsalgorithmus:
a = [1,2,3,4, ... 1000]
b = [1001,1002,1003,1004, ... 2000]
Oder
a = [1,2,3,4, ... 1000]
b = [0,100,200, ... 1000]
Es gibt einige Fälle, in denen der einfache Zusammenführungsalgorithmus optimal ist
a = [1,3,5,7,9,....,999]
b = [2,4,6,8,10,....,1000]
Daher sollte der Algorithmus im Idealfall n + m-1 Vergleiche in angemessener Weise herabsetzen und maximal durchführen, falls die Arrays verschachtelt sind oder zumindest nicht wesentlich schlechter sind.
Eine Sache, die sich für Listen mit einem großen Größenunterschied recht gut eignet, ist die Verwendung der binären Suche, um die Elemente des kleineren Arrays in das größere Array einzufügen. Dies verschlechtert sich jedoch nicht, wenn beide Listen gleich groß und verschachtelt sind.
Das einzige, was für die Elemente verfügbar ist, ist eine (Gesamt-) Ordnungsfunktion, so dass ein Schema, das Vergleiche billiger macht, nicht möglich ist.
Irgendwelche Ideen?
Ich habe mir dieses Stück in Scala ausgedacht . Ich glaube, es ist in Bezug auf die Anzahl der Vergleiche optimal, aber ich kann es nicht beweisen. Zumindest ist es viel einfacher als die Dinge, die ich in der Literatur gefunden habe.
Und seit dem ursprünglichen Posting habe ich einen Blog-Post darüber geschrieben, wie das funktioniert.
quelle
Antworten:
Der normale Zusammenführungssortieralgorithmus - Zusammenführungsschritt, bei dem normalerweise n + m -1 Vergleiche angewendet werden, wobei eine Liste die Größe n und die andere die Größe m hat. Die Verwendung dieses Algorithmus ist die einfachste Methode, um zwei sortierte Listen zu kombinieren.
Wenn die Vergleiche zu teuer sind, können Sie zwei Dinge tun - entweder Sie minimieren die Anzahl der Vergleiche oder Sie minimieren die Kosten für Vergleiche.
Konzentrieren wir uns auf die Minimierung der Vergleichskosten. Sie und nur Sie können entscheiden, ob die zu vergleichenden Daten quantisiert werden können oder nicht. Wenn Sie sie quantisieren können, ist dies eine Form der Implementierung einer Hash-Methode, die die Reihenfolge beibehält. ZB wenn Ihre Daten nach Name verglichen werden, dann der erste tname, ... Sie können den ersten zu Buchstaben des Namens "Klaehn, Ruediger" nehmen und Ihr Datenelement zu "Kl.Ru" reduzieren / quantisieren, wenn Sie es vergleichen Bei "Packer, The" behalten Sie die Reihenfolge "Pa.Th" bei - Sie können jetzt einen günstigeren Vergleichsalgorithmus anwenden und die reduzierten Werte vergleichen. Wenn Sie jedoch ein anderes "Kl.Ru" finden, haben Sie jetzt einen nahen Wert und wechseln möglicherweise zu einem teureren Ansatz, wenn Sie diese Elemente vergleichen.
Wenn Sie diesen quantisierten Wert aus Ihren Daten extrahieren können, anstatt ihn zu vergleichen, vergleichen Sie zuerst den quantisierten oder gehashten Wert. Bitte beachten Sie, dass dieser Wert nur einmal berechnet werden muss, damit Sie ihn beim Erstellen des Datenelements berechnen können.
Ich erwähnte auch einen anderen Weg, um Ihre Vergleiche zu minimieren.
Ich habe mir das klassische Buch TAOCP-Volume 3-Sorting and Searching (S. 197-207, Abschnitt 5.3.2) angesehen, das 10 Seiten zu diesem Thema enthält. Ich habe zwei Hinweise auf Algorithmen gefunden, die schneller sind als n + m-1 Vergleiche.
Da ist zum einen der Hwang-Lin-Merge-Algorithmus und zum anderen eine Verbesserung von Glenn K Manacher - beide werden von TAOCP und ein Algorithmus von Christen angeführt, der sich der Untergrenze der benötigten Vergleiche unter speziellen Bedingungen für die Länge n und m nähert der Listen.
Der Algorithmus von Manacher wurde im Journal of the ACM Vol vorgestellt. 26 Nummer 3 auf den Seiten 434-440: "Signifikante Verbesserungen des" Hwan-Lin "-Mischalgorithmus". Die Liste mit m Elementen und die Liste mit n Elementen können unterschiedlich lang sein, sie müssen jedoch auch nach der Anzahl der Elemente geordnet sein, die sie enthalten. m <= n
Der Hwang-Lin-Algorithmus zerlegt die zusammenzuführenden Listen in kleinere Listen und sortiert die Listen, indem er das erste Element jeder Unterliste vergleicht und entscheidet, ob einige Elemente in der Unterliste verglichen werden müssen oder nicht. Ist die erste Liste kleiner als die zweite Liste, so ist die Chance groß, dass aufeinanderfolgende Elemente der längeren Liste ohne Vergleich in die resultierende Liste übernommen werden können. Ist das erste Element der kleinen Liste größer als das erste Element der geteilten größeren Liste, können alle Elemente vor der Unterliste ohne Vergleich kopiert werden.
Eine durchschnittliche Fallanalyse des Verschmelzungsalorithmus von Hwang und Lin (Vega, Frieze, Santha) in Abschnitt 2 enthält einen Pseudocode des HL-Algorithmus. Welches ist viel besser als meine Beschreibung. Und Sie können sehen, warum es weniger Vergleiche gibt - der Algorithmus verwendet eine binäre Suche, um den Index zu finden, in den das Element aus der kürzeren Liste eingefügt werden kann.
Wenn die Listen nicht wie in Ihrem letzten Beispiel verschachtelt sind, sollten Sie in den meisten Fällen eine kleinere und eine größere Liste haben. Dies ist der Zeitpunkt, an dem der HL-Algorithmus eine bessere Leistung erzielt.
quelle
Angenommen, die beiden Arrays haben N- und M-Elemente, N ≥ M, und alle Elemente sind unterschiedlich.
Wenn das sortierte Array ein Element x von N gefolgt von einem Element y von M oder umgekehrt enthält, müssen x und y verglichen worden sein, sonst würden wir nicht wissen, in welcher Reihenfolge sie gehören. (Es kann keine Kette von anderen Elementen a, b, c geben, bei denen wir beispielsweise wissen, dass x <a <b <c <y ist, weil es keine Elemente zwischen x und y gibt. Daher müssen x und y verglichen worden sein direkt.
Wenn N> M ist, ist es möglich, ein Array zu haben, in dem jedem Element von M ein Element von N vorangestellt und gefolgt wird. Dies bedeutet, dass mindestens 2 M Vergleiche erforderlich sind - auch wenn Sie einen nicht deterministischen Sortieralgorithmus verwenden, der dies ermöglicht eine perfekte Vermutung, welche Zahlen zu vergleichen sind. (Was das bedeutet: Angenommen, Sie haben N große, M = 1. Die binäre Suche dauert O (log2 N) Schritte; ein nicht deterministischer Algorithmus würde erraten, zu welchen zwei Elementen das eine Element des zweiten Arrays gehört, und zwei Vergleiche anstellen bestätige die Vermutung).
quelle