Effiziente Möglichkeit, eine Zahl in ein sortiertes Array von Zahlen einzufügen?

142

Ich habe ein sortiertes JavaScript-Array und möchte ein weiteres Element in das Array einfügen, sodass das resultierende Array sortiert bleibt. Ich könnte sicherlich eine einfache Einfügefunktion im QuickSort-Stil implementieren:

var array = [1,2,3,4,5,6,7,8,9];
var element = 3.5;
function insert(element, array) {
  array.splice(locationOf(element, array) + 1, 0, element);
  return array;
}

function locationOf(element, array, start, end) {
  start = start || 0;
  end = end || array.length;
  var pivot = parseInt(start + (end - start) / 2, 10);
  if (end-start <= 1 || array[pivot] === element) return pivot;
  if (array[pivot] < element) {
    return locationOf(element, array, pivot, end);
  } else {
    return locationOf(element, array, start, pivot);
  }
}

console.log(insert(element, array));

[WARNUNG] Dieser Code hat einen Fehler beim Versuch, an den Anfang des Arrays einzufügen, z. B. insert(2, [3, 7 ,9]) erzeugt falsche [3, 2, 7, 9].

Ich habe jedoch festgestellt, dass Implementierungen der Array.sort-Funktion dies möglicherweise für mich tun können, und zwar nativ:

var array = [1,2,3,4,5,6,7,8,9];
var element = 3.5;
function insert(element, array) {
  array.push(element);
  array.sort(function(a, b) {
    return a - b;
  });
  return array;
}

console.log(insert(element, array));

Gibt es einen guten Grund, die erste Implementierung der zweiten vorzuziehen?

Bearbeiten : Beachten Sie, dass im allgemeinen Fall eine O-Einfügung (log (n)) (wie im ersten Beispiel implementiert) schneller ist als ein generischer Sortieralgorithmus. Dies ist jedoch insbesondere bei JavaScript nicht unbedingt der Fall. Beachten Sie, dass:

  • Der beste Fall für mehrere Einfügealgorithmen ist O (n), das sich immer noch erheblich von O (log (n)) unterscheidet, aber nicht ganz so schlecht wie O (n log (n)) ist, wie unten erwähnt. Dies hängt vom jeweiligen verwendeten Sortieralgorithmus ab (siehe Implementierung von Javascript Array.sort? ).
  • Die Sortiermethode in JavaScript ist eine native Funktion, sodass potenziell große Vorteile erzielt werden können - O (log (n)) mit einem großen Koeffizienten kann für Datensätze mit angemessener Größe immer noch viel schlechter sein als O (n).
Elliot Kroo
quelle
Die Verwendung von Spleiß in der zweiten Implementierung ist etwas verschwenderisch. Warum nicht Push verwenden?
Breton
Guter Punkt, ich habe es gerade von Anfang an kopiert.
Elliot Kroo
4
Alles, was enthält splice()(z. B. Ihr 1. Beispiel), ist bereits O (n). Selbst wenn intern keine neue Kopie des gesamten Arrays erstellt wird, müssen möglicherweise alle n Elemente um 1 Position zurückgeschoben werden, wenn das Element an Position 0 eingefügt werden soll. Vielleicht ist es schnell, weil es eine native Funktion ist und die Konstante ist niedrig, aber es ist trotzdem O (n).
j_random_hacker
6
Für zukünftige Referenzzwecke für Benutzer, die diesen Code verwenden, weist der Code einen Fehler auf, wenn versucht wird, ihn an den Anfang des Arrays einzufügen. Suchen Sie weiter unten nach dem korrigierten Code.
Pinocchio
3
parseIntVerwenden Sie Math.floorstattdessen nicht use . Math.floorist viel schneller als parseInt: jsperf.com/test-parseint-and-math-floor
Hubert Schölnast

Antworten:

58

Nur als einzelner Datenpunkt habe ich dies für Kicks getestet, indem ich 1000 zufällige Elemente in ein Array von 100.000 vorsortierten Zahlen mit den beiden Methoden unter Verwendung von Chrome unter Windows 7 eingefügt habe:

First Method:
~54 milliseconds
Second Method:
~57 seconds

Zumindest bei diesem Setup macht die native Methode dies nicht wett. Dies gilt auch für kleine Datenmengen, bei denen 100 Elemente in ein Array von 1000 eingefügt werden:

First Method:
1 milliseconds
Second Method:
34 milliseconds
Sam Phillips
quelle
1
arrays.sort klingt ziemlich schrecklich
njzk2
2
Scheint, dass die array.splice etwas wirklich Kluges tun muss, um ein einzelnes Element innerhalb von 54 Mikrosekunden einzufügen.
Gnasher729
@ gnasher729 - Ich denke nicht, dass Javascript-Arrays wirklich mit physisch kontinuierlichen Arrays wie in C identisch sind. Ich denke, dass die JS-Engines sie als Hash-Map / Wörterbuch implementieren können, um das schnelle Einfügen zu ermöglichen.
Ian
1
Wenn Sie eine Komparatorfunktion mit verwenden Array.prototype.sort, verlieren Sie die Vorteile von C ++, weil die JS-Funktion so oft aufgerufen wird.
Aleclarson
Wie vergleicht sich die erste Methode jetzt, da Chrome TimSort verwendet ? Aus TimSort Wikipedia : "Im besten Fall, wenn die Eingabe bereits sortiert ist, läuft [TimSort] in linearer Zeit."
vornehmster
47

Einfach ( Demo ):

function sortedIndex(array, value) {
    var low = 0,
        high = array.length;

    while (low < high) {
        var mid = (low + high) >>> 1;
        if (array[mid] < value) low = mid + 1;
        else high = mid;
    }
    return low;
}
Webdesigner
quelle
4
Nette Geste. Ich habe noch nie davon gehört, bitweise Operatoren zu verwenden, um den Mittelwert zweier Zahlen zu ermitteln. Normalerweise würde ich nur mit 0,5 multiplizieren. Gibt es auf diese Weise einen signifikanten Leistungsschub?
Jackson
2
@ Jackson x >>> 1ist eine binäre Rechtsverschiebung um 1 Position, was effektiv nur eine Division durch 2 ist. ZB für 11: 1011-> 101Ergebnisse zu 5.
Qwerty
3
@Qwerty @Web_Designer Sein bereits auf dieser Strecke, könnte man den Unterschied zwischen erklären >>> 1und ( gesehen hier und dort ) >> 1?
Yckart
4
>>>ist eine vorzeichenlose Rechtsverschiebung, während sie >>das Vorzeichen erweitert - alles läuft auf die speicherinterne Darstellung negativer Zahlen hinaus, wobei das hohe Bit gesetzt wird, wenn es negativ ist. Wenn Sie also mit 0b10001 nach rechts verschieben, >>erhalten Sie 0b1100, wenn Sie stattdessen verwenden, erhalten >>>Sie 0b0100. Während es in dem in der Antwort angegebenen Fall nicht wirklich wichtig ist (die Zahl, die verschoben wird, ist weder größer als der Maximalwert einer vorzeichenbehafteten positiven 32-Bit-Ganzzahl noch negativ), ist es wichtig, in diesen beiden Fällen die richtige zu verwenden (Sie müssen auswählen, welchen Fall Sie behandeln müssen).
Asherkin
2
@asherkin - Dies ist nicht richtig: "Wenn Sie um 0b10001 Stelle nach rechts verschieben, >>erhalten Sie 0b1100". Nein, du verstehst 0b0100. Das Ergebnis der verschiedenen Rechtsverschiebungsoperatoren ist für alle Werte gleich, mit Ausnahme von negativen Zahlen und Zahlen größer als 2 ^ 31 (dh Zahlen mit einer 1 im ersten Bit).
Gilly3
29

Sehr gute und bemerkenswerte Frage mit einer sehr interessanten Diskussion! Ich habe die Array.sort()Funktion auch verwendet, nachdem ich ein einzelnes Element in einem Array mit einigen Tausend Objekten verschoben hatte.

Ich musste Ihre locationOfFunktion für meinen Zweck erweitern, weil ich komplexe Objekte habe und daher eine Vergleichsfunktion wie in Array.sort():

function locationOf(element, array, comparer, start, end) {
    if (array.length === 0)
        return -1;

    start = start || 0;
    end = end || array.length;
    var pivot = (start + end) >> 1;  // should be faster than dividing by 2

    var c = comparer(element, array[pivot]);
    if (end - start <= 1) return c == -1 ? pivot - 1 : pivot;

    switch (c) {
        case -1: return locationOf(element, array, comparer, start, pivot);
        case 0: return pivot;
        case 1: return locationOf(element, array, comparer, pivot, end);
    };
};

// sample for objects like {lastName: 'Miller', ...}
var patientCompare = function (a, b) {
    if (a.lastName < b.lastName) return -1;
    if (a.lastName > b.lastName) return 1;
    return 0;
};
kwrl
quelle
7
Es scheint erwähnenswert zu sein, dass diese Version korrekt funktioniert, wenn versucht wird, sie an den Anfang des Arrays einzufügen. (Es ist erwähnenswert, weil die Version in der ursprünglichen Frage einen Fehler hat und für diesen Fall nicht richtig funktioniert.)
Garyrob
3
Ich bin nicht sicher, ob meine Implementierung anders war, aber ich musste den Ternär ändern return c == -1 ? pivot : pivot + 1;, um den richtigen Index zurückzugeben. Andernfalls würde die Funktion für ein Array mit der Länge 1 -1 oder 0 zurückgeben.
Niel
3
@James: Die Parameter start und end werden nur bei rekursiven Aufrufen verwendet und nicht bei ersten Aufrufen. Da dies Indexwerte für das Array sind, müssen sie vom Typ Integer sein, und bei einem rekursiven Aufruf wird dies implizit angegeben.
Kwrl
1
@ TheRedPea: Nein, ich meinte >> 1sollte schneller (oder nicht langsamer) sein als/ 2
kwrl
1
Ich kann ein potenzielles Problem mit dem Ergebnis der comparerFunktion erkennen. In diesem Algorithmus ist es im Vergleich zu , +-1aber es könnte willkürlicher Wert sein <0/ >0. Siehe Vergleichsfunktion . Der problematische Teil ist nicht nur die switchAussage, sondern auch die Linie: if (end - start <= 1) return c == -1 ? pivot - 1 : pivot;wo cwird auch verglichen -1.
eXavier
19

Ihr Code enthält einen Fehler. Es sollte lauten:

function locationOf(element, array, start, end) {
  start = start || 0;
  end = end || array.length;
  var pivot = parseInt(start + (end - start) / 2, 10);
  if (array[pivot] === element) return pivot;
  if (end - start <= 1)
    return array[pivot] > element ? pivot - 1 : pivot;
  if (array[pivot] < element) {
    return locationOf(element, array, pivot, end);
  } else {
    return locationOf(element, array, start, pivot);
  }
}

Ohne dieses Update kann der Code niemals ein Element am Anfang des Arrays einfügen.

synthetischer Null
quelle
warum oringst du ein int mit 0? dh was fängt an || 0 tun?
Pinocchio
3
@ Pinocchio: Start || 0 ist ein kurzes Äquivalent von: if (! Start) start = 0; - Die "längere" Version ist jedoch effizienter, da sie sich selbst keine Variable zuweist.
SuperNova
11

Ich weiß, dass dies eine alte Frage ist, die bereits eine Antwort hat, und es gibt eine Reihe anderer anständiger Antworten. Ich sehe einige Antworten, die vorschlagen, dass Sie dieses Problem lösen können, indem Sie den korrekten Einfügeindex in O (log n) nachschlagen - Sie können, aber Sie können in dieser Zeit nicht einfügen, da das Array teilweise kopiert werden muss, um es zu erstellen Platz.

Fazit: Wenn Sie wirklich O (log n) Einfügungen und Löschungen in ein sortiertes Array benötigen, benötigen Sie eine andere Datenstruktur - kein Array. Sie sollten einen B-Baum verwenden . Die Leistungssteigerungen, die Sie durch die Verwendung eines B-Tree für einen großen Datensatz erzielen, werden die hier angebotenen Verbesserungen in den Schatten stellen.

Wenn Sie ein Array verwenden müssen. Ich biete den folgenden Code basierend auf der Einfügesortierung an, der genau dann funktioniert, wenn das Array bereits sortiert ist. Dies ist nützlich für den Fall, dass Sie nach jedem Einsatz neu greifen müssen:

function addAndSort(arr, val) {
    arr.push(val);
    for (i = arr.length - 1; i > 0 && arr[i] < arr[i-1]; i--) {
        var tmp = arr[i];
        arr[i] = arr[i-1];
        arr[i-1] = tmp;
    }
    return arr;
}

Es sollte in O (n) arbeiten, was meiner Meinung nach das Beste ist, was Sie tun können. Wäre schöner, wenn js Mehrfachzuweisungen unterstützen würde. Hier ist ein Beispiel zum Spielen:

Aktualisieren:

das könnte schneller sein:

function addAndSort2(arr, val) {
    arr.push(val);
    i = arr.length - 1;
    item = arr[i];
    while (i > 0 && item < arr[i-1]) {
        arr[i] = arr[i-1];
        i -= 1;
    }
    arr[i] = item;
    return arr;
}

JS Bin Link aktualisiert

domoarigato
quelle
In JavaScript ist die von Ihnen vorgeschlagene Einfügesortierung langsamer als die binäre Such- und Spleißmethode, da Spleiß eine schnelle Implementierung hat.
Trincot
Ich bin skeptisch, es sei denn, Javascript kann irgendwie gegen die Gesetze der Zeitkomplexität verstoßen. Haben Sie ein ausführbares Beispiel dafür, wie die binäre Such- und Spleißmethode schneller ist?
Domoarigato
Ich nehme meinen zweiten Kommentar zurück ;-) In der Tat wird es eine Arraygröße geben, ab der eine B-Baum-Lösung die Spleißlösung übertrifft.
Trincot
9

Ihre Einfügefunktion setzt voraus, dass das angegebene Array sortiert ist. Sie sucht direkt nach dem Ort, an dem das neue Element eingefügt werden kann, normalerweise indem Sie nur einige der Elemente im Array betrachten.

Die allgemeine Sortierfunktion eines Arrays kann diese Verknüpfungen nicht verwenden. Offensichtlich müssen zumindest alle Elemente im Array überprüft werden, um festzustellen, ob sie bereits korrekt angeordnet sind. Diese Tatsache allein macht die allgemeine Sortierung langsamer als die Einfügefunktion.

Ein generischer Sortieralgorithmus ist normalerweise im Durchschnitt O (n ⋅ log (n)) und abhängig von der Implementierung kann es tatsächlich der schlimmste Fall sein, wenn das Array bereits sortiert ist, was zu Komplexitäten von O (n 2 ) führt . Die direkte Suche nach der Einfügeposition hat stattdessen nur eine Komplexität von O (log (n)) , sodass sie immer viel schneller ist.

etw
quelle
Es ist erwähnenswert, dass das Einfügen eines Elements in ein Array eine Komplexität von O (n) aufweist, sodass das Endergebnis ungefähr gleich sein sollte.
NemPlayer
5

Für eine kleine Anzahl von Artikeln ist der Unterschied ziemlich trivial. Wenn Sie jedoch viele Elemente einfügen oder mit einem sehr großen Array arbeiten, verursacht das Aufrufen von .sort () nach jedem Einfügen einen enormen Overhead.

Am Ende habe ich genau für diesen Zweck eine ziemlich raffinierte binäre Such- / Einfügefunktion geschrieben, also dachte ich, ich würde sie teilen. Da whileanstelle der Rekursion eine Schleife verwendet wird, werden zusätzliche Funktionsaufrufe nicht belauscht, sodass die Leistung meiner Meinung nach sogar noch besser ist als bei den ursprünglich veröffentlichten Methoden. Standardmäßig Array.sort()wird der Standardkomparator emuliert , auf Wunsch wird jedoch eine benutzerdefinierte Komparatorfunktion akzeptiert.

function insertSorted(arr, item, comparator) {
    if (comparator == null) {
        // emulate the default Array.sort() comparator
        comparator = function(a, b) {
            if (typeof a !== 'string') a = String(a);
            if (typeof b !== 'string') b = String(b);
            return (a > b ? 1 : (a < b ? -1 : 0));
        };
    }

    // get the index we need to insert the item at
    var min = 0;
    var max = arr.length;
    var index = Math.floor((min + max) / 2);
    while (max > min) {
        if (comparator(item, arr[index]) < 0) {
            max = index;
        } else {
            min = index + 1;
        }
        index = Math.floor((min + max) / 2);
    }

    // insert the item
    arr.splice(index, 0, item);
};

Wenn Sie andere Bibliotheken verwenden möchten, bietet lodash die Funktionen sortiertIndex und sortiertLastIndex , die anstelle der whileSchleife verwendet werden können. Die beiden möglichen Nachteile sind: 1) Die Leistung ist nicht so gut wie bei meiner Methode (ich bin mir nicht sicher, wie viel schlechter sie ist) und 2) Sie akzeptiert keine benutzerdefinierte Komparatorfunktion, sondern nur eine Methode, um den zu vergleichenden Wert zu erhalten (Ich nehme an, mit dem Standardkomparator).

Sean die Bohne
quelle
Der Aufruf an arr.splice()ist sicherlich O (n) Zeitkomplexität.
Domoarigato
4

Hier einige Gedanken: Wenn Sie sich wirklich Gedanken über die Laufzeit Ihres Codes machen, sollten Sie zunächst wissen, was passiert, wenn Sie die integrierten Funktionen aufrufen! Ich weiß nicht von oben nach unten in Javascript, aber ein kurzer Blick auf die Spleißfunktion hat dies zurückgegeben , was darauf hindeutet, dass Sie bei jedem Aufruf ein ganz neues Array erstellen! Ich weiß nicht, ob es wirklich darauf ankommt, aber es hängt sicherlich mit der Effizienz zusammen. Ich sehe, dass Breton in den Kommentaren bereits darauf hingewiesen hat, aber es gilt sicherlich für jede Array-Manipulationsfunktion, die Sie wählen.

Wie auch immer, um das Problem tatsächlich zu lösen.

Als ich las, dass Sie sortieren wollten, war mein erster Gedanke, die Einfügesortierung zu verwenden ! . Dies ist praktisch, da es in linearer Zeit auf sortierten oder nahezu sortierten Listen ausgeführt wird . Da Ihre Arrays nur 1 Element außerhalb der Reihenfolge haben, gilt dies als nahezu sortiert (mit Ausnahme von Arrays der Größe 2 oder 3 oder was auch immer, aber zu diesem Zeitpunkt, komm schon). Nun, die Implementierung der Sortierung ist nicht schlecht, aber es ist ein Ärger, mit dem Sie sich vielleicht nicht befassen möchten, und auch hier weiß ich nichts über Javascript und ob es einfach oder schwer sein wird oder so. Dadurch entfällt die Notwendigkeit Ihrer Suchfunktion, und Sie drücken einfach (wie von Breton vorgeschlagen).

Zweitens scheint Ihre "Quicksort-ähnliche" Suchfunktion ein binärer Suchalgorithmus zu sein! Es ist ein sehr schöner Algorithmus, intuitiv und schnell, aber mit einem Haken: Es ist bekanntermaßen schwierig, ihn richtig zu implementieren. Ich werde es nicht wagen zu sagen, ob deins korrekt ist oder nicht (ich hoffe es ist natürlich! :)), aber sei vorsichtig, wenn du es benutzen willst.

Zusammenfassung: Die Verwendung von "push" mit Einfügesortierung funktioniert in linearer Zeit (vorausgesetzt, der Rest des Arrays ist sortiert) und vermeidet unordentliche Anforderungen an den binären Suchalgorithmus. Ich weiß nicht, ob dies der beste Weg ist (die zugrunde liegende Implementierung von Arrays, vielleicht macht es eine verrückte eingebaute Funktion besser, wer weiß), aber es scheint mir vernünftig. :) - Agor.

agorenst
quelle
1
+1, weil alles, was enthält, splice()bereits O (n) ist. Selbst wenn intern keine neue Kopie des gesamten Arrays erstellt wird, müssen möglicherweise alle n Elemente um 1 Position zurückgeschoben werden, wenn das Element an Position 0 eingefügt werden soll.
j_random_hacker
Ich glaube, die Einfügesortierung ist auch O (n) bester Fall und O (n ^ 2) schlechtester Fall (obwohl der Anwendungsfall des OP wahrscheinlich der beste Fall ist).
Domoarigato
Minus eins für das Gespräch mit dem OP. Der erste Absatz fühlte sich wie eine unnötige Ermahnung an, nicht zu wissen, wie Spleiß unter der Haube funktioniert
Matt Zera
2

Hier ist ein Vergleich von vier verschiedenen Algorithmen, um dies zu erreichen: https://jsperf.com/sorted-array-insert-comparison/1

Algorithmen

Naiv ist immer schrecklich. Es scheint für kleine Array-Größen, die anderen drei unterscheiden sich nicht zu sehr, aber für größere Arrays übertreffen die letzten 2 den einfachen linearen Ansatz.

gabtub
quelle
Warum nicht Datenstrukturen testen, die ein schnelles Einfügen und Suchen ermöglichen? Ex. Überspringlisten und BSTs. stackoverflow.com/a/59870937/3163618
qwr
Wie vergleicht Native jetzt, wo Chrome TimSort verwendet ? Aus TimSort Wikipedia : "Im besten Fall, wenn die Eingabe bereits sortiert ist, läuft sie in linearer Zeit."
vornehmster
2

Hier ist eine Version, die lodash verwendet.

const _ = require('lodash');
sortedArr.splice(_.sortedIndex(sortedArr,valueToInsert) ,0,valueToInsert);

Hinweis: sortedIndex führt eine binäre Suche durch.

I. Cantrell
quelle
1

Die beste Datenstruktur, die ich mir vorstellen kann, ist eine indizierte Sprungliste, die die Einfügeeigenschaften verknüpfter Listen mit einer Hierarchiestruktur beibehält, die Protokollzeitoperationen ermöglicht. Im Durchschnitt können Such-, Einfüge- und Direktzugriffssuchen in O (log n) -Zeit durchgeführt werden.

Ein Auftragsstatistikbaum ermöglicht die Indizierung der Protokollzeit mit einer Rangfunktion.

Wenn Sie keinen Direktzugriff benötigen, aber O (log n) einfügen und nach Schlüsseln suchen müssen, können Sie die Array-Struktur verlassen und jede Art von binärem Suchbaum verwenden .

Keine der Antworten, die verwendet array.splice()werden, ist überhaupt effizient, da dies durchschnittlich O (n) Zeit ist. Was ist die zeitliche Komplexität von array.splice () in Google Chrome?

qwr
quelle
Wie kommt diese AntwortIs there a good reason to choose [splice into location found] over [push & sort]?
Greybeard
1
@ Greybeard Es beantwortet den Titel. zynisch ist keine Wahl effizient.
qwr
Keine der beiden Optionen könnte effizient sein, wenn viele Elemente eines Arrays kopiert werden.
qwr
1

Hier ist meine Funktion, verwendet die binäre Suche, um einen Artikel zu finden und fügt ihn dann entsprechend ein:

function binaryInsert(val, arr){
    let mid, 
    len=arr.length,
    start=0,
    end=len-1;
    while(start <= end){
        mid = Math.floor((end + start)/2);
        if(val <= arr[mid]){
            if(val >= arr[mid-1]){
                arr.splice(mid,0,val);
                break;
            }
            end = mid-1;
        }else{
            if(val <= arr[mid+1]){
                arr.splice(mid+1,0,val);
                break;
            }
            start = mid+1;
        }
    }
    return arr;
}

console.log(binaryInsert(16, [
    5,   6,  14,  19, 23, 44,
   35,  51,  86,  68, 63, 71,
   87, 117
 ]));

Oguz Yilmaz
quelle
0

Sortieren Sie nicht nach jedem Artikel neu, es ist übertrieben.

Wenn nur ein Element eingefügt werden muss, können Sie den einzufügenden Speicherort mithilfe der binären Suche finden. Verwenden Sie dann memcpy oder ähnliches, um die verbleibenden Elemente in großen Mengen zu kopieren und Platz für das eingefügte Element zu schaffen. Die binäre Suche ist O (log n) und die Kopie ist O (n), was O (n + log n) ergibt. Mit den oben beschriebenen Methoden führen Sie nach jeder Einfügung eine Neusortierung durch, die O (n log n) ist.

Ist das wichtig? Nehmen wir an, Sie fügen zufällig k Elemente ein, wobei k = 1000 ist. Die sortierte Liste umfasst 5000 Elemente.

  • Binary search + Move = k*(n + log n) = 1000*(5000 + 12) = 5,000,012 = ~5 million ops
  • Re-sort on each = k*(n log n) = ~60 million ops

Wenn die k Elemente, die eingefügt werden sollen, immer eintreffen, müssen Sie suchen + verschieben. Wenn Sie jedoch eine Liste mit k Elementen erhalten, die Sie vorab in ein sortiertes Array einfügen können, können Sie dies noch besser machen. Sortieren Sie die k Elemente getrennt vom bereits sortierten n-Array. Führen Sie dann eine Scan-Sortierung durch, bei der Sie beide sortierten Arrays gleichzeitig nach unten verschieben und ineinander verschmelzen. - Einstufige Zusammenführungssortierung = k log k + n = 9965 + 5000 = ~ 15.000 Operationen

Update: Bezüglich Ihrer Frage.
First method = binary search+move = O(n + log n). Second method = re-sort = O(n log n)Erklärt genau die Zeiten, die Sie erhalten.

Rama Hoetzlein
quelle
Ja, aber nein, das hängt von Ihrem Sortieralgorithmus ab. Wenn Sie eine Blasensortierung in umgekehrter Reihenfolge verwenden, ist Ihre Sortierung, wenn das letzte Element nicht sortiert ist, immer in o (n)
njzk2
-1
function insertOrdered(array, elem) {
    let _array = array;
    let i = 0;
    while ( i < array.length && array[i] < elem ) {i ++};
    _array.splice(i, 0, elem);
    return _array;
}
Yachthafen
quelle