Was ist die zeitliche Komplexität des Ein- und Ausreihens einer Warteschlange, die mit einer einfach verknüpften Liste implementiert wurde?


7

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.


7
Bitte entfernen Sie keine wichtigen Informationen aus Ihrer Frage, sobald Sie eine Antwort erhalten haben. Wir möchten, dass die beiden Fragen und Antworten in Zukunft für andere nützlich sind. Versuchen Sie also, die Dinge vollständig zu halten.
Diskrete Eidechse

Antworten:


14

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 != nullund tail != null):

function enqueue(value) {
    node = new Node(value)     // O(1)
    tail.next = node           // O(1)
    tail = node                // O(1)
    size++                     // O(1)
}

Daraus können wir schließen, dass die zeitliche Komplexität ist Ö(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 sollte null:

Pseudocode (unter der Annahme, dass head != nullund tail != null):

function dequeue() {
    value = head.value         // O(1)
    head = head.next           // O(1)
    size--                     // O(1)

    if (head == null) {        // O(1)
        tail = null            // O(1)
    }

    return value               // O(1)
}

Alle diese Operationen haben Ö(1) Zeitkomplexität, die die Zeitkomplexität der Dequeue-Funktion erhöht Ö(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öhtÖ(n).

Wenn Sie beispielsweise den Schwanz entfernen möchten, ist die zeitliche Komplexität hoch Ö(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 != nullund tail != null):

function removeLast() {

    // Edge case when there is only 1 element in the queue.
    if (head == tail) {                   // O(1)
        value = head.value                // O(1)
        head = null                       // O(1)
        tail = null                       // O(1)

        return value                      // O(1)
    }

    // Searching for the new tail.
    newTail = head                        // O(1)
    while (newTail.next != tail) {        // O(n)
        newTail = newTail.next            // O(1)
    }

    value = tail.value                    // O(1)
    newTail.next = null                   // O(1)
    tail = newTail                        // O(1)

    return tail                           // O(1)    
}

Daraus ist ersichtlich, dass die zeitliche Komplexität tatsächlich ist Ö(n).


Enqueue verarbeitet keine leere Liste. Während die Warteschlange behandelt wird, wenn die Liste leer wird.
Ratschenfreak

1

Der Kommentar im Buch geht anscheinend davon aus, dass Ihre Implementierung einer verknüpften Liste zwei Zeiger enthält, headdie auf den ersten Knoten in der Liste und lastauf den letzten Knoten verweisen.

Bei diesem Design ist das Anhängen an die Liste einfach:

list.last.next = newNode;
list.last = newNode;

Um den letzten Knoten zu entfernen, müssen Sie jedoch den vorletzten Knoten finden, damit Sie seine nextVerknüpfung löschen und den lastZeiger so ändern können , dass er darauf zeigt. Dies erfordert das Scannen der Liste, um den Knoten zu finden, an dem node.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.

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.