Hinzufügen von Elementen zu einem sortierten Array


31

Was wäre der schnellste Weg, um dies zu tun (sowohl aus algorithmischer als auch aus praktischer Sicht)?

Ich dachte etwas in der folgenden Richtung.

Ich könnte das Ende eines Arrays ergänzen und dann bubblesort verwenden, da es einen Best Case (am Anfang komplett sortiertes Array) hat, der in der Nähe liegt und eine lineare Laufzeit hat (im besten Fall).

Wenn ich andererseits weiß, dass ich mit einem sortierten Array beginne, kann ich mithilfe einer binären Suche die Einfügemarke für ein bestimmtes Element ermitteln.

Meine Vermutung ist, dass der zweite Weg fast optimal ist, aber neugierig, was da draußen ist.

Wie geht das am besten?


1
Wenn Sie dies häufig tun müssen, ist es am schnellsten, überhaupt kein Array zu verwenden.
Reinierpost

Selbstausgleichender Binärbaum, meinst du?
Soandos

Ja, möglicherweise; siehe die antworten ...
reinierpost

Antworten:


25

Wir zählen die Anzahl der Lese- und Schreibvorgänge von Array-Elementen. Für die Blasensortierung benötigen Sie Zugriffe (das erste Schreiben bis zum Ende, im schlimmsten Fall zwei Lesevorgänge und zwei Schreibvorgänge für n Tauschvorgänge). Für die binäre Suche benötigen wir 2 log n + 2 n + 1 ( 2 log n für die binäre Suche, dann im schlimmsten Fall 2 n , um die Array-Elemente nach rechts zu verschieben, und 1, um das Array-Element zu schreiben seine richtige Position).1+4nn2logn+2n+12logn2n

Beide Methoden sind also für Array-Implementierungen gleich komplex, aber die binäre Suchmethode erfordert auf lange Sicht weniger Array-Zugriffe ... asymptotisch gesehen halb so viele. Natürlich spielen auch andere Faktoren eine Rolle.

Tatsächlich könnten Sie bessere Implementierungen verwenden und nur die tatsächlichen Array-Zugriffe zählen (keine Zugriffe auf das einzufügende Element). Sie könnten für die Blasensortierung ausführen und n + 2 n + 1 für die Binärsuche protokollieren. Wenn also der Register- / Cache-Zugriff billig und der Array-Zugriff teuer ist, suchen Sie vom Ende und verschieben sich auf dem Weg (intelligenter) Blasensortierung zum Einfügen) könnte besser sein, wenn auch nicht asymptotisch.2n+1logn+2n+1

Eine bessere Lösung könnte die Verwendung einer anderen Datenstruktur beinhalten. Arrays geben Ihnen O (1) -Zugriffe (Direktzugriff), aber Einfügungen und Löschungen können kosten. Eine Hash-Tabelle könnte O (1) -Einfügungen und -Löschungen enthalten, die Zugriffe würden kosten. Andere Optionen umfassen BSTs und Heaps usw. Es kann sich lohnen, die Verwendungsanforderungen Ihrer Anwendung für das Einfügen, Löschen und Zugreifen zu berücksichtigen und eine spezialisiertere Struktur zu wählen.

Beachten Sie, dass auch wenn Sie hinzufügen möchten Elemente zu einem sortierten Array von n Elementen, könnte eine gute Idee Art die effizient sein m Elemente, dann die beiden Arrays verschmelzen; Außerdem können sortierte Arrays effizient erstellt werden, indem z. B. Heaps (Heap-Sortierung) verwendet werden.mnm


1
"Eine Hash-Tabelle könnte O (1) -Einfügungen und -Löschungen enthalten" - normalerweise abgeschrieben.
Raphael

8
Amortisiert erwartet .
JeffE

BST hat zum Suchen und Einfügen (Wikipedia). Warum ist es hier nicht die am besten empfohlene Wahl? O ( 2 l o g n ) zum Suchen und Einfügen. O(log n)O(2 log n)
Kashyap,

8

Wenn Sie einen Grund haben, den Heap nicht zu verwenden, sollten Sie die Einfügesortierung anstelle der Blasensortierung verwenden. Es ist besser, wenn Sie einige unsortierte Elemente haben.


7

O(n)

O(lgn)O(n+lgn)O(n)

O(1)

Wie auch immer, ich sehe keinen Grund, die Luftblasen für dieses Problem zu entfernen.


2
O

+1 für Snarky .. :-)
Kashyap

4

Patrick87 hat das alles sehr gut erklärt. Eine zusätzliche Optimierung, die Sie vornehmen könnten, wäre die Verwendung eines kreisförmigen Puffers: Sie können Elemente wie gewohnt rechts von der Position des eingefügten Elements nach rechts verschieben. Sie können aber auch Elemente nach links von der richtigen Position nach links verschieben. Dazu müssen Sie das Array als kreisförmig behandeln, dh, das letzte Element befindet sich direkt vor dem ersten. Außerdem müssen Sie den Index dort beibehalten, wo die Elemente gerade beginnen.

Wenn Sie dies tun, kann dies bedeuten, dass Sie ungefähr halb so viele Array-Zugriffe ausführen (unter der Annahme einer gleichmäßigen Verteilung der Indizes, in die Sie einfügen). Bei der binären Suche nach der Position ist es trivial zu wählen, ob nach links oder rechts verschoben werden soll. Bei der Blasen-Sortierung müssen Sie vor dem Start richtig „raten“. Dies ist jedoch ganz einfach: Vergleichen Sie einfach das eingefügte Element mit dem Median des Arrays, was bei einem einzelnen Array-Zugriff möglich ist.


4

Ich habe den Sortieralgorithmus für Einfügungen effektiv für dieses Problem verwendet. Zu einer Zeit, als wir ein Leistungsproblem mit einem Hash-Tabellenobjekt hatten, habe ich ein neues Objekt geschrieben, das stattdessen die Binärsuche verwendete und die Leistung erheblich verbesserte. Um die Liste sortiert zu halten, wird die Anzahl der Elemente protokolliert, die seit der letzten Sortierung hinzugefügt wurden (dh die Anzahl der nicht sortierten Elemente), wenn die Liste aufgrund einer Suchanforderung sortiert werden musste. In Abhängigkeit davon wurde eine Einfügesortierung oder eine schnelle Sortierung durchgeführt auf den Prozentsatz der Artikel unsortiert. Die Verwendung der Einfügesorte war der Schlüssel zur Verbesserung der Leistung.


Haben Sie ein formelles Ergebnis bezüglich der amortisierten Betriebskosten? Und willkommen!
Raphael
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.