Warum wird in der Mitte einer verknüpften Liste O (1) eingefügt?

104

Gemäß dem Wikipedia-Artikel über verknüpfte Listen wird das Einfügen in die Mitte einer verknüpften Liste als O (1) betrachtet. Ich würde denken, es wäre O (n). Müssen Sie nicht den Knoten suchen, der sich am Ende der Liste befinden könnte?

Berücksichtigt diese Analyse nicht das Auffinden der Knotenoperation (obwohl dies erforderlich ist) und nur das Einfügen selbst?

EDIT :

Verknüpfte Listen haben gegenüber Arrays mehrere Vorteile. Das Einfügen eines Elements an einem bestimmten Punkt einer Liste ist eine Operation mit konstanter Zeit, während das Einfügen in ein Array möglicherweise das Verschieben der Hälfte der Elemente oder mehr erfordert.

Die obige Aussage ist für mich etwas irreführend. Korrigieren Sie mich, wenn ich falsch liege, aber ich denke, die Schlussfolgerung sollte lauten:

Arrays:

  • Finden des Einfüge- / Löschpunktes O (1)
  • Einfügen / Löschen durchführen O (n)

Verknüpfte Listen:

  • Finden des Einfüge- / Löschpunktes O (n)
  • Einfügen / Löschen durchführen O (1)

Ich denke, das einzige Mal, dass Sie die Position nicht finden müssten, wäre, wenn Sie eine Art Zeiger darauf behalten würden (wie in einigen Fällen mit Kopf und Schwanz). Wir können also nicht einfach sagen, dass verknüpfte Listen immer Arrays für Einfüge- / Löschoptionen schlagen.

Rob Sobers
quelle

Antworten:

113

Sie haben Recht, der Artikel betrachtet "Indizierung" als separate Operation. Das Einfügen ist also selbst O (1), aber das Erreichen dieses mittleren Knotens ist O (n).

CookieOfFortune
quelle
3
Was einen größeren Unterschied macht, wenn mehr als 1 Objekt an derselben Position
eingefügt wird
@ Anony-Mousse kannst du es ein bisschen mehr erklären? dh wir müssen die Einfügeposition nur einmal finden, wenn wir mehrere Objekte einfügen?
MyTitle
2
Es ist O (n) in der Größe der vorhandenen Liste, nicht die Anzahl der Einfügungen, die Sie dort vornehmen möchten.
Hat aufgehört - Anony-Mousse
27

Die Einfügung selbst ist O (1). Die Knotenfindung ist O (n).

Evansbee
quelle
24

Nein, wenn Sie sich entscheiden, dass Sie einfügen möchten, wird davon ausgegangen, dass Sie sich gerade in der Iteration der Liste befinden.

Operationen an verknüpften Listen werden häufig so ausgeführt, dass sie nicht wirklich als generische "Liste", sondern als Sammlung von Knoten behandelt werden. Stellen Sie sich den Knoten selbst als Iterator für Ihre Hauptschleife vor. Wenn Sie also durch die Liste stöbern, stellen Sie als Teil Ihrer Geschäftslogik fest, dass ein neuer Knoten hinzugefügt (oder ein alter gelöscht) werden muss, und Sie tun dies. Sie können 50 Knoten in einer einzigen Iteration hinzufügen, und jeder dieser Knoten ist nur O (1) die Zeit, um zwei benachbarte Knoten zu trennen und Ihren neuen einzufügen.

Bearbeiten: Mann, Sie geben einen zweiten Absatz ein und plötzlich, anstatt der Ersthelfer zu sein, sind Sie der 5., der dasselbe sagt wie die ersten 4!

Bill K.
quelle
1
Ha ja, das ist scheiße ... ich + 1 wäre deins, weil es sich lohnt zu erwähnen, dass die Komplexität beim Einfügen verknüpfter Listen im Zusammenhang damit betrachtet wird, bereits am gewünschten Zeiger zu sein.
Daniel Macias
6

Zum Vergleich mit einem Array, wie in diesem Diagramm dargestellt, ist es O (1), da Sie nicht alle Elemente nach dem neuen Knoten verschieben müssen.

Ja, sie gehen davon aus, dass Sie bereits den Zeiger auf diesen Knoten haben oder dass das Abrufen des Zeigers trivial ist. Mit anderen Worten, das Problem wird angegeben: " Wenn der Knoten bei X angegeben ist , welchen Code muss nach diesem Knoten eingefügt werden?" Sie können am Einfügepunkt beginnen.

Joel Coehoorn
quelle
5

Das Einfügen in eine verknüpfte Liste unterscheidet sich vom Durchlaufen. Sie finden das Element nicht, sondern setzen Zeiger zurück, um das Element dort abzulegen. Es spielt keine Rolle, ob es in der Nähe des vorderen Endes oder in der Nähe des Endes eingefügt wird. Beim Einfügen werden immer noch Zeiger neu zugewiesen. Es hängt natürlich davon ab, wie es implementiert wurde, aber das ist die Stärke von Listen - Sie können sie einfach einfügen. Beim Zugriff über den Index leuchtet ein Array. Für eine Liste ist es jedoch normalerweise O (n), um das n-te Element zu finden. Zumindest erinnere ich mich daran aus der Schule.

itsmatt
quelle
3

Weil es keine Schleife beinhaltet.

Das Einfügen ist wie folgt:

  • Element einfügen
  • Link zum vorherigen
  • Link zum nächsten
  • getan

Dies ist in jedem Fall eine konstante Zeit.

Folglich ist das Einfügen von n Elementen nacheinander O (n).

Tomalak
quelle
3

Berücksichtigt diese Analyse nicht das Auffinden der Knotenoperation (obwohl dies erforderlich ist) und nur das Einfügen selbst?

Du hast es. Beim Einfügen an einem bestimmten Punkt wird davon ausgegangen, dass Sie bereits einen Zeiger auf das Element halten, nach dem Sie einfügen möchten:

InsertItem(item * newItem, item * afterItem)
James
quelle
2

Das Einfügen ist O (1), sobald Sie wissen, wo Sie es ablegen werden.

Lance Richardson
quelle
2

Nein, die Suche wird nicht berücksichtigt. Wenn Sie jedoch bereits einen Zeiger auf ein Element in der Mitte der Liste haben, ist das Einfügen an dieser Stelle O (1).

Wenn Sie danach suchen müssen, müssen Sie die Zeit für die Suche hinzufügen, die O (n) sein sollte.

TED
quelle
0

Der Artikel befasst sich mit dem Vergleich von Arrays mit Listen. Das Finden der Einfügeposition für Arrays und Listen ist O (N), daher ignoriert der Artikel sie.


quelle
1
Wäre es nicht O (1), die Einfügemarke eines Arrays zu finden? Da Arrays im zusammenhängenden Speicher gespeichert sind, muss lediglich der Offset hinzugefügt werden.
Rob Sobers
@ vg1890 - Sie müssen zuerst den Offset finden.
0

O (1) hängt davon ab, dass Sie einen Artikel haben, in den Sie den neuen Artikel einfügen. (vorher oder nachher). Wenn Sie dies nicht tun, ist es O (n), da Sie diesen Gegenstand finden müssen.

Glenn
quelle
0

Ich denke, es ist nur ein Fall von dem, was Sie für die O () - Notation zählen. Beim Einfügen der zu zählenden normalen Operation handelt es sich um Kopieroperationen. Bei einem Array müssen Sie beim Einfügen in die Mitte alles über den Speicherort kopieren. Bei einer verknüpften Liste werden zwei Zeiger gesetzt. Sie müssen den Ort finden, egal was eingefügt werden soll.

workmad3
quelle
0

Wenn Sie die Referenz des Knotens haben, der nach der Operation eingefügt werden soll, ist O (1) für eine verknüpfte Liste.
Für ein Array ist es immer noch O (n), da Sie alle aufeinander folgenden Knoten verschieben müssen.

Sani Singh Huttunen
quelle
0

Die häufigsten Fälle sind wahrscheinlich das Einfügen am Anfang oder am Ende der Liste (und das Finden der Listenenden dauert möglicherweise nicht lange).

Vergleichen Sie dies mit dem Einfügen von Elementen am Anfang oder am Ende eines Arrays (was eine Größenänderung des Arrays am Ende oder eine Größenänderung und Verschiebung aller Elemente am Anfang erfordert).

ChrisW
quelle
Es ist möglich, das Einfügen von Elementen in das Ende eines Arrays auf O (1) zu setzen, wenn Sie am Ende einen Puffer mit leeren Elementen behalten, obwohl die Einfügungen gelegentlich immer noch O (1) sind. Die meisten Sammlungen tun dies. Es ist auch möglich, das Inertisieren von Elementen am Anfang eines Arrays auf O (1) zu setzen, indem Sie Ihren Indexoperator so ändern, dass die Elementnummer (n + x)% len zurückgegeben wird, wobei x die Häufigkeit ist, mit der Sie Elemente am Anfang eingefügt haben der Liste. Deques werden manchmal so implementiert (aber manchmal auch mit doppelt verknüpften Listen.
Brian