Verkettete Liste

Wenn wir mit sequentiellen Daten arbeiten, greifen wir normalerweise auf Listen (Arrays) zurück, um die Daten zu speichern und zu verwalten. In manchen Fällen kann es jedoch vorteilhafter sein, eine verkettete Liste (Linked List) zu verwenden – insbesondere dann, wenn häufig Elemente am Anfang der Liste eingefügt oder entfernt werden sollen, da diese Operationen oft schneller ausgeführt werden können.
Eine verkettete Liste zählt zu den grundlegendsten Datenstrukturen. Wie bei einer gewöhnlichen Liste/Array können wir Elemente hinzufügen und abrufen. Bei verketteten Listen sprechen wir jedoch von einzelnen „Nodes“, die neben den Daten auch einen Verweis auf den nächsten „Node“ enthalten. In einer einfach verketteten Liste besitzt jedes Element (der Node) einen Zeiger auf das nächste Element, während das letzte Element einen Verweis auf nichts (null) hat. In der Fachliteratur wird das erste Element einer einfach verketteten Liste „head“ genannt und das letzte Element „tail“. Eine mögliche Implementierung einer verketteten Liste kann so aussehen:
class Node:
    def __init__(self, data):
        self.data = data               # Speichert die Daten
        self.after = None              # Speichert einen Verweis auf das nächste Element


class LinkedList:
    def __init__(self):
        self.head = None               # Anfänglich sind keine Elemente vorhanden

    def append(self, data):            # Fügt ein neues Element zur Liste hinzu
        new_node = Node(data)          # Erstellt einen Node, der 'data' enthält
        if self.head is None:          # Wenn die Liste noch leer ist
            self.head = new_node       # Wird der Kopf auf den neuen Node gesetzt
            return
        current = self.head            # Beginnend beim Kopf durch die Liste gehen
        while current.after:           # Solange das Ende (tail) nicht erreicht ist
            current = current.after    # Zum nächsten Node wechseln
        current.after = new_node       # Den tail aktualisieren und auf den neuen Node setzen

    def print(self):                   # Gibt alle Elemente in der Liste aus
        current = self.head            # Start beim Kopf
        while current:                 # Solange das Ende nicht erreicht ist
            print(current.data, end='\n' if current.after is None else ' --> ')
            current = current.after    # Zum nächsten Node wechseln


names = LinkedList()                   # Eine leere verkettete Liste erstellen
names.append('Anna')                   # Anna zur Liste hinzufügen
names.append('Bob')                    # Bob zur Liste hinzufügen
names.append('Sona')                   # Sona zur Liste hinzufügen
names.print()                          # Anna --> Bob --> Sona
notion image
In dieser Implementierung haben wir zwei Klassen: Node und LinkedList. Die Klasse Node besitzt zwei Attribute: data und after. Das Attribut data enthält den Wert des Nodes, während after den Verweis auf den nächsten Node in der Liste speichert. Die Klasse LinkedList verfügt über ein Attribut: head, das auf das erste Element in der Liste verweist. Die Methode append() dient dazu, einen neuen Node ans Ende der Liste anzuhängen, während die Methode print() alle Elemente der Liste ausgibt.

Doppelt verkettete Liste

Darüber hinaus gibt es auch doppelt verkettete Listen („doubly linked lists“). Hier besitzt jedes Element sowohl einen Verweis auf das nachfolgende als auch auf das vorherige Element. Dadurch kann die Liste in beide Richtungen durchlaufen werden.

Analyse von verketteten Listen

Wichtige Punkte, die man bei verketteten Listen beachten sollte:
  • Das Auffinden eines bestimmten Elements in einer verketteten Liste benötigt Zeit, da man vom Kopf aus die Liste durchlaufen muss, um das Element zu finden.
  • Kennt man jedoch den Node, nach dem ein neues Element eingefügt werden soll, so ist das Einfügen selbst in möglich, da lediglich die Verweise der Nachbar-Elemente aktualisiert werden müssen.
  • Ebenso benötigt das Entfernen eines bekannten Node nur , weil auch hier lediglich die Verweise angepasst werden müssen.
  • Verkettete Listen benötigen mehr Speicherplatz als Arrays, da in jedem Element neben den Daten ein zusätzlicher Verweis gespeichert wird.

Aufgabe

Gegeben sind n Abfragen, die ausgeführt werden sollen. Es gibt 2 Arten von Abfragen:
  1. Füge eine Zahl am Anfang der Liste ein.
  1. Gib die gesamte Liste aus.

Eingabe

Die erste Zeile der Eingabe enthält eine einzelne ganze Zahl n (1 ≤ n ≤ 1000), die Anzahl der Abfragen.
Die nächsten n Zeilen enthalten die Abfragen – print, falls die gesamte Liste ausgegeben werden soll, und insert x, wenn die Zahl x am Anfang der Liste eingefügt werden soll ( ≤ x ≤ ).

Ausgabe

Das Programm soll alle Abfragen korrekt ausführen und die Liste mit Leerzeichen zwischen den Elementen ausgeben.

Beispiele

Eingabe
Ausgabe
6 insert 8 print insert 10 insert -2 insert -6 print
8 -6 -2 10 8
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue