Ich versuche, die zeitliche Komplexität einer Warteschlange zu verstehen, die mit einer verknüpften Listendatenstruktur implementiert ist. Mein Buch sagt, dass wir eine Warteschlange in O (1) -Zeit implementieren können durch:
- Warteschlange auf der Rückseite
- an der Spitze aus der Warteschlange
und es heißt auch
Beachten Sie, dass das Hinzufügen eines Elements zum Schwanz zwar eine konstante Zeit ist, das Entfernen eines Elements aus dem Schwanz jedoch O (n) ist, da wir den neuen Schwanz finden müssen
Ich weiß, dass das Hinzufügen eines neuen Knotens zu meiner Warteschlange am Kopf (Enqueue) O (1) erfordert, da ich den Kopfzeiger habe. In ähnlicher Weise wird beim Entfernen eines Knotens am Kopf (Dequeue) auch O (1) benötigt. Aber ich verstehe nicht, warum das Hinzufügen eines Elements auf der Rückseite (Enqueue) O (1) benötigt, während das Entfernen (Dequeue) O (n) benötigt. Für mich wäre es sinnvoller, wenn die Warteschlange hinten eher O (n) als O (1) benötigt, da in beiden Fällen (Hinzufügen / Entfernen hinten) der Endzeiger gefunden werden müsste und daher durchquert werden müsste die gesamte Liste.
Antworten:
Enqueueing
Sie müssen nicht die gesamte Liste durchlaufen, um das neue Ende zu finden. Sie müssen lediglich einen neuen Knoten hinzufügen, auf den das aktuelle Ende zeigt, und diesen Knoten als neues Ende festlegen.
Pseudocode (unter der Annahme, dass
head != null
undtail != null
):Daraus können wir schließen, dass die zeitliche Komplexität istO ( 1 ) .
Dequeueing
Für die Warteschlange müssen wir nur den nächsten Knoten des aktuellen Kopfes als neuen Kopf festlegen und den Wert des alten Kopfes zurückgeben.
Hinweis : Vergessen Sie nicht, dass, wenn der neue Kopf auf eingestellt ist
null
, auch der Schwanz auf eingestellt sein solltenull
:Pseudocode (unter der Annahme, dass
head != null
undtail != null
):Alle diese Operationen habenO ( 1 ) Zeitkomplexität, die die Zeitkomplexität der Dequeue-Funktion erhöht O ( 1 ) auch.
Suchen
Die Suche nach einem Wert erfolgt durch Durchsuchen aller Elemente, beginnend mit dem Kopf. Im schlimmsten Fall müssten Sie die gesamte Warteschlange durchlaufen, was die Zeitkomplexität im schlimmsten Fall erhöhtO ( n ) .
Wenn Sie beispielsweise den Schwanz entfernen möchten, ist die zeitliche Komplexität hochO ( n ) . Dies ist , weil Sie den neuen Schwanz für die Warteschlange finden müßten und da der Schwanz ist nicht Zugriff auf das vorherige Element in einer einfach verketteten Liste hat, müßten Sie die gesamte Warteschlange für den neuen Schwanz suchen.
Pseudocode (unter der Annahme, dass
head != null
undtail != null
):Daraus ist ersichtlich, dass die zeitliche Komplexität tatsächlich istO ( n ) .
quelle
Der Kommentar im Buch geht anscheinend davon aus, dass Ihre Implementierung einer verknüpften Liste zwei Zeiger enthält,
head
die auf den ersten Knoten in der Liste undlast
auf den letzten Knoten verweisen.Bei diesem Design ist das Anhängen an die Liste einfach:
Um den letzten Knoten zu entfernen, müssen Sie jedoch den vorletzten Knoten finden, damit Sie seine
next
Verknüpfung löschen und denlast
Zeiger so ändern können , dass er darauf zeigt. Dies erfordert das Scannen der Liste, um den Knoten zu finden, an demnode.next == list.last
.Es ist denkbar
list.secondToLast
, dass Sie auch einen Zeiger haben, aber das löst das Problem nicht, denn wenn Sie den letzten Knoten entfernen, müssen Sie diesen ändern, um auf den vorherigen dritten bis letzten Knoten zu verweisen , und dieses Problem tritt auf die gesamte Liste zurück.quelle