Theorieblatt 11

Werbung
1.2 Liste erstellen
Informatik I - Übung 11
Liste, Queue und Stack
Nehmen wir an, wir wollen eine Liste von 3 Knoten erstellen. Wir müssen dafür zuerst die
Liste initialisieren und dann mit Hilfe einer Schleife die erstellten Knoten mit den gewünschten
Werten füllen :
Daniel Hentzen
1
[email protected]
2
3
14. Mai 2014
4
Node ∗ head ; // head p o i n t e r e r s t e l l e n
Node ∗ newNode ; // p o i n t e r a u f neuen Knoten e r s t e l l e n
i n t num ; // Wert
head = NULL ; // head z e i g t am Anfang a u f N u l l e l e m e n t , w e i l noch ←k e i n Knoten e x i s t i e r t
5
6
7
8
9
1 Linked Lists
10
11
Eine Liste ist eine Ansammlung von verketteten Knoten. Jeder Knoten speichert zwei
Komponenten : einen Wert und die Adresse (Pointer) des nächsten Knotens.
12
13
14
Zu jeder Liste gehört ein “head”-pointer. Dieser soll auf den ersten Knoten der Liste zeigen (=
dessen Adresse speichern).
15
Der Pointer des letzten Knotens speichert die Adresse “NULL”, zeigt also auf das Nullelement.
Dies zeigt das Ende der Liste an.
f o r ( i n t i = 0 ; i < 3 ; i++) // 3 Knoten
{
cout << ” Enter number : ” ;
cin >> num ;
newNode = new Node ;
newNode−>data = num ;
newNode−>next = head ;
head = newNode ;
}
Erklärung :
• Zeile 11 : Mit new weisen wir Speicherplatz für einen neuen Knoten zu und speichern
dessen Adresse im newNode pointer den wir in Zeile 2 erstellt haben.
• Zeile 12 : Jetzt initialisieren wir die data-Komponente des Knotens auf den eingelesenen
Wert.
Bem. : Da newNode ein pointer auf ein Node ist, können wir nicht einfach mit
dem . Operator auf die member-Variablen zugreifen. Stattdessen benutzen wir entweder (∗newNode).data (Dereferenzierung und dann Zugriff) oder den −> Operator, der
Dereferenzierung und Zugriff in sich vereint.
1.1 Implementierung der Knoten
• Zeile 13 : Wir übergeben die Adresse des nächsten Knotens an die next-Komponente des
neuen Knotens. Da wir diesen vorne “einfädeln”, entspricht diese Adresse immer dem
aktuellen head-Pointer.
Die Knoten werden als structs implementiert :
s t r u c t nodeType {
i n t data ;
nodeType ∗ next ;
};
t y p e d e f s t r u c t nodeType Node ; // Node = nodeType ( a l i a s )
• Zeile 14 : Der head pointer zeigt im Moment auf das zweite Element, da wir ja ein neues
“eingefädelt” haben. Darum setzen wir den head pointer wieder auf das erste Element,
also auf den neuen Knoten.
1
Um einen neuen Knoten einzusetzen, benötigen wir einen pointer (current) auf den Knoten vor
dem einzusetzenden Knoten.
1.3 Liste durchlaufen
1
1
2
3
4
5
6
7
2
Node ∗ current ;
current = head ; // S t a r t
w h i l e ( current != NULL )
{
cout << current−>data << ” ” ;
current = current−>next ; // n a e c h s t e r Knoten
}
3
4
// n e u e r Knoten :
Node ∗ newNode ;
newNode = new Node ;
newNode−>data = 3 7 ;
5
6
7
8
// E i n s e t z e n :
newNode−>next = current−>next ;
current−>next = newNode ;
Erklärung :
Erklärung :
• Zeile 1 : Wir brauchen einen pointer der von Knoten zu Knoten springt. Wir nennen ihn
current.
• Zeile 2,3 : Speicherplatz für neuen Knoten zuweisen und Adresse im newNode pointer
speichern.
• Zeile 2 : Wir starten beim ersten Element, current muss also am Anfang dessen Adresse
speichern.
• Zeile 7 : Der next-Teil des neuen Knotens soll die Adresse des Knotens nach current
speichern.
• Zeile 3 : Wir haben gesehen dass die next-Komponente des letzten Knotens der Liste auf
das Nullelement zeigt. Sobald das next des current-Knoten also NULL ist, sind wir beim
letzten Knoten angekommen und wir brechen die Schleife ab.
• Zeile 8 : Der next-Teil des current Knotens soll die Adresse des neuen Knotens speichern.
Achtung auf Reihenfolge !
• Zeile 6 : Der current pointer wird auf den nächsten Knoten gesetzt, dessen Adresse im
aktuellen Knoten gespeichert ist.
1.6 Knoten löschen
1.4 Element finden
Node ∗ current ;
current = head ; // S t a r t
i n t element = 1 2 ; // Element , das w i r suchen
w h i l e ( current != NULL )
{
i f ( current−>data == element )
b r e a k ; // S c h l e i f e wird a b g e b r o c h e n
Wir brauchen wieder einen current pointer auf den Knoten vor dem zu löschenden Knoten.
Ausserdem brauchen wir einen pointer auf den zu löschenden Knoten selbst.
current = current−>next ; // n a e c h s t e r Knoten
}
// R e s u l t a t : c u r r e n t z e i g t a u f g e f u n d e n e s Element
1
2
3
4
Node ∗ deleteNode ;
deleteNode = current−>next ;
current−>next = deleteNode−>next ;
d e l e t e deleteNode ;
Erklärung :
• Zeile 2 : deleteNode soll auf den zu löschenden Knoten zeigen, muss also die Adresse vom
Knoten hinter dem current-Knoten speichern.
1.5 Neuen Knoten einsetzen
• Zeile 3 : Die next Komponente des current Knotens muss jetzt die Adresse des
übernächsten Knotens speichern, das heisst muss gleich dem next des zu löschenden
Knotens sein.
• Zeile 4 : Erst jetzt können wir das Objekt mit delete löschen.
2
2.2 Element hinzufügen am Ende (einreihen)
1.7 Doubly linked Lists
Hier hat jeder Knoten zwei pointers : einen next und einen previous pointer.
1
2
3
4
5
6
Node ∗ v = new Node ;
s t r u c t nodeType {
i n t data ;
nodeType ∗ next ;
nodeType ∗ prev ;
};
t y p e d e f s t r u c t nodeType dNode ;
tail−>next = v ;
tail = v ;
v−>next = NULL ;
2.3 Element löschen am Anfang
2 Queues
Eine Queue (“Schlange”) ist eine Liste, in der man neue Knoten hinten anhängt und Knoten
vorne löscht. Dieses Prinzip nennt man “First In First Out” (FIFO).
Zusätzlich zum head pointer gibt es hier auch noch einen tail pointer um den letzten Knoten
zu bezeichnen.
Node ∗ v = head ;
head = head−>next ;
delete v ;
3 Stacks
Stacks sind “one-sided” queues (Stapel). Man kann nur am Anfang hinzufügen (=push) und
am Anfang löschen (=pop). Dieses Prinzip nennt man ”Last In First Out”(LIFO).
2.1 Implementierung der Knoten
s t r u c t nodeType {
i n t data ;
nodeType ∗ next ;
};
t y p e d e f s t r u c t nodeType Node ;
Node ∗ head = NULL ;
Node ∗ tail = NULL ;
3
3.1 Knoten hinzufügen : push
Node ∗ v = new Node ;
v−>next = head ;
head = v ;
3.2 Knoten entfernen : pop
Node ∗ v = head ;
head = head−>next ;
delete v ;
4
Herunterladen