• Keine Ergebnisse gefunden

¨Ubungspaket 32 Einfach verkettete, sortierte Liste

N/A
N/A
Protected

Academic year: 2021

Aktie "¨Ubungspaket 32 Einfach verkettete, sortierte Liste"

Copied!
15
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Ubungspaket 32 ¨

Einfach verkettete, sortierte Liste

Ubungsziele: ¨

1. Aufbau einer einfach verketteten, sortierten Liste 2. Traversieren von Listen

3. Vereinfachung durch ein Dummy-Element Skript:

Kapitel: 75 und insbesondere ¨ Ubungspaket 29 und 31 Semester:

Wintersemester 2021/22 Betreuer:

Thomas, Tim und Ralf Synopsis:

In diesem ¨ Ubungspaket werden wir endlich eine einfach verkettete, sor-

tierte Liste programmieren. Dabei orientieren wir uns an der in der

Vorlesung vorgestellten Wirth’schen Variante, die das Programmieren

deutlich vereinfacht. Da das Programmieren sortierter Listen erst mal

recht komplex ist, werden wir die wesentlichen Aspekte wiederholen

bzw. gezielt darauf hin arbeiten. Also, nicht verzweifeln, sondern ein-

fach probieren. . .

(2)

Teil I: Stoffwiederholung

Aufgabe 1: Allgemeine Fragen zu Listen

Erkl¨are mit eigenen Worten, was eine einfach verkettete, sortierte Liste ist.

Was versteht man unter

”Traversieren“?

Was ist der Unterschied zwischen einer linearen, sortierten Liste und einem Stack?

Aufgabe 2: Detailfragen zu Listen

Die folgenden Fragen beziehen sich immer auf eine einfach verkettete, sortierte Liste oder deren Elemente.

Wie viele Nachfolger hat jedes Element?

Wie viele Vorg¨anger hat jedes Element?

Woran erkennt man das Listenende?

Wie findet man den Listenanfang?

Wie kann man eine Liste ausgeben?

Wie kann man sie invertiert ausgeben?

Wie muss man sich das vorstellen?

(3)

Aufgabe 3: Einf¨ ugen neuer Elemente in eine Liste

Im Skript haben wir recht ausf¨uhrlich ¨uber die algorithmische Umsetzung des sortierten Einf¨ugens geschrieben. Zur Rekapitulation haben wir eine Reihe von Fragen zusammenge- tragen.

Welche vier F¨alle muss man beim Einf¨ugen neuer Elemente beachten?

1.

2.

3.

4.

In wie vielen F¨allen wird der Startzeiger ver¨andert?

Ist das programmiertechnisch gut oder schlecht?

Warum?

In den meisten F¨allen benutzt man eine Schleife, um diejenige Stelle zu finden, an der man einf¨ugen m¨ochte. Welches Programmierproblem ergibt sich dadurch?

Aufgabe 4: Die Wirth’sche Variante

Im Skript haben wir auch die Variante von Wirth diskutiert. Was ist die wesentliche Idee?

Die Wirth’sche Idee hat einige Besonderheiten und Vorteile. Hierzu folgende Fragen:

Wird der Startzeiger ver¨andert?

Wie viele F¨alle werden unterschieden?

Wof¨ur ist das Dummy Element?

Wo bleibt der

”Suchzeiger“ stehen?

Wie wird dann aber eingef¨ugt?

Welchen Algorithmus nehmen wir?

(4)

Teil II: Quiz

Aufgabe 1: Positionierung innerhalb von Listen

Nehmen wir an, wir haben die folgende Definition einer Liste sowie die folgende Funktion zur Positionierung eines Zeigers.

1 t y p e d e f s t r u c t u s e r { int i ; } D A T A ; 2

3 t y p e d e f s t r u c t _ e l e m e n t {

4 s t r u c t _ e l e m e n t * n e x t ;

5 D A T A d a t a ;

6 } ELEMENT , * EP ;

7

8 EP p o s i t i o n ( EP listp , int val )

9 {

10 w h i l e ( listp - > d a t a . i < val ) 11 l i s t p = listp - > n e x t ;

12 r e t u r n l i s t p ;

13 }

Nun gehen wir davon aus, dass wir bereits die folgende Liste (in unserem Hauptprogramm) aufgebaut haben:

start next:

i : 1

next:

i : 3

next:

i : 5

next:

i : 7

Auf welche Elemente zeigen die Zeiger start und p nach folgenden Funktionsaufrufen:

Funktionsaufruf start p Anmerkung

p = position( start, 3 ) . . . . . . . . . . . .

p = position( start, -1 ) . . . . . . . . . . . .

p = position( start->next, -1 ) . . . . . . . . . . . .

p = position( start, 6 ) . . . . . . . . . . . .

p = position( start, 7 ) . . . . . . . . . . . .

p = position( start, 8 ) . . . . . . . . . . . .

Schlussfolgerung:

(5)

Aufgabe 2: Positionierung: zweiter Versuch

Aufgrund des vorherigen Programmabsturzes bei Suchwerten, die gr¨oßer als das gr¨oßte Element der Liste waren, haben wir unser Programm wie folgt ver¨andert:

1 t y p e d e f s t r u c t u s e r { int i ; } D A T A ; 2

3 t y p e d e f s t r u c t _ e l e m e n t {

4 s t r u c t _ e l e m e n t * n e x t ;

5 D A T A d a t a ;

6 } ELEMENT , * EP ;

7

8 EP p o s i t i o n ( EP listp , int val )

9 {

10 w h i l e ( listp - > next - > d a t a . i < val ) 11 l i s t p = listp - > n e x t ;

12 r e t u r n l i s t p ;

13 }

Wir betrachten wieder die gleiche Liste sowie die gleichen Funktionsaufrufe:

start next:

i : 1

next:

i : 3

next:

i : 5

next:

i : 7

Auf welche Elemente zeigen die Zeiger start und p nach folgenden Funktionsaufrufen:

Funktionsaufruf start p Anmerkung

p = position( start, 3 ) . . . . . . . . . . . .

p = position( start, -1 ) . . . . . . . . . . . .

p = position( start->next, -1 ) . . . . . . . . . . . .

p = position( start, 6 ) . . . . . . . . . . . .

p = position( start, 7 ) . . . . . . . . . . . .

p = position( start, 8 ) . . . . . . . . . . . .

Schlussfolgerung:

(6)

Aufgabe 3: Positionierung: dritter Versuch

So richtig sch¨on waren die beiden vorherigen Versuche nicht. Versuchen wir es also noch- mals, diesmal mit einem etwas modifizierten Algorithmus sowie einer modifizierten Liste.

1 t y p e d e f s t r u c t u s e r { int i ; } D A T A ; 2

3 t y p e d e f s t r u c t _ e l e m e n t {

4 s t r u c t _ e l e m e n t * n e x t ;

5 D A T A d a t a ;

6 } ELEMENT , * EP ;

7

8 EP p o s i t i o n ( EP listp , int val )

9 {

10 w h i l e ( listp - > d a t a . i < val && listp - > n e x t != 0 ) 11 l i s t p = listp - > n e x t ;

12 r e t u r n l i s t p ;

13 }

start next:

i : 1

next:

i : 5

next:

i : 7

next:

i : BIG

Auf welche Elemente zeigen die Zeiger start und p nach folgenden Funktionsaufrufen:

Funktionsaufruf start p Anmerkung

p = position( start, 3 ) . . . . . . . . . . . .

p = position( start, -1 ) . . . . . . . . . . . .

p = position( start, 6 ) . . . . . . . . . . . .

p = position( start, 7 ) . . . . . . . . . . . .

p = position( start, 8 ) . . . . . . . . . . . .

Schlussfolgerung:

Position von p:

(7)

Aufgabe 4: Speicherallokation

Gegeben sei folgendes Programmst¨uck:

1 t y p e d e f s t r u c t u s e r { int i ; } D A T A ; 2

3 t y p e d e f s t r u c t _ e l e m e n t {

4 s t r u c t _ e l e m e n t * n e x t ;

5 D A T A d a t a ;

6 } ELEMENT , * EP ;

7

8 EP n e w E l e m e n t ( int val , EP n e x t )

9 {

10 EP new = m a l l o c ( s i z e o f ( E L E M E N T ) ) ;

11 if ( new )

12 {

13 new - > d a t a . i = val ; new - > n e x t = n e x t ;

14 }

15 r e t u r n new ;

16 }

Vervollst¨andige das Speicherbild f¨ur die folgenden beiden Aufrufe vonnewElement(). Wie bei fast allen ¨Ubungen gehen wir davon aus, dass sowohlint-Werte als auch Zeiger immer vier Bytes im Arbeitsspeicher belegen. Ferner nehmen wir an, dass der Aufruf der Funktion newElement() die Adresse 0xFA00 liefert.

1. EP p = newElement( 4711, 0 );

Segment: . . . . Adresse Variable Wert 0xFE7C EP p:

Segment: . . . . Adresse Wert

0xFA04 0xFA00 2. ELEMENT el; EP p = newElement( 815, & el );

Segment: . . . .

Adresse Variable Wert

0xFE7C el.data.i:

0xFE78 el.next :

0xFE74 EP p :

Segment: . . . . Adresse Wert

0xFA04 0xFA00

Vielen hilft es beim Verstehen, wenn sie zus¨atzlich noch die Zeiger in die Speicherbildchen einzeichnen.

(8)

Aufgabe 5: Elemente einf¨ ugen

F¨ur die beiden letzten Quizaufgaben haben wir den Positionierungsalgorithmus aus Auf- gabe 3 um ein paar Zeilen erweitert. Der erste Parameter dieser neuen Funktion ist die bisher im Arbeitsspeicher aufgebaute Liste. Der zweite Parameter ist ein Zeiger auf ein neues Element, wie wir es gerade eben in der vorherigen Aufgabe gesehen haben:

1 v o i d i n s e r t E l e m e n t ( EP list , EP new )

2 {

3 D A T A tmp ;

4 w h i l e ( list - > d a t a . i < new - > d a t a . i && list - > n e x t != 0 ) 5 l i s t = list - > n e x t ;

6 tmp = new - > d a t a ;

7 * new = * l i s t ;

8 list - > n e x t = new ; 9 list - > d a t a = tmp ;

10 }

In den beiden folgenden Aufgaben wird die Funktion insertElement() immer mit der selben Liste aufgerufen. Sie hat nur einDatenelement.Beim ersten Mal wird das Datenele- ment5, beim zweiten Mal 13 eingef¨ugt. Der in den Abbildungen verwendete start-Zeiger ist der im Hauptprogramm verwaltete Startzeiger der Liste. Er dient nur zur Illustrierung und wird nicht weiter verwendet. Bearbeite nun die beiden F¨alle:

1. Einf¨ugen des

”Datenelementes“ 5: Zeile 3:

next:

i : 9

next:

i : BIG next:

i : 5

new start

Ende Zeile 9:

next:

i :

next:

i :

next:

i :

new start list

(9)

2. Einf¨ugen des

"Datenelementes\ 13: Zeile 3:

next:

i : 9

next:

i : BIG next:

i : 13 new

start

Ende Zeile 9:

next:

i :

next:

i :

next:

i :

new start list

Damit w¨aren wir jetzt f¨ur den Anwendungsfall ger¨ustet.

(10)

Teil III: Fehlersuche

Aufgabe 1: Ausgabe von Listen

Die meisten Fehler- und Problemf¨alle haben wir bereits besprochen. Doch Dr. L. Ist- Wirth hat das Ausgeben Wirth’scher Listen noch nicht im Griff. Was lief hier schief. . . ?

1 v o i d p r t L i s t ( EP p )

2 {

3 p r i n t f ( " L i s t e : " ) ;

4 do {

5 p = p - > n e x t ;

6 p r i n t f ( " % i " , p - > d a t a . i ) ;

7 } w h i l e ( p != 0 ) ;

8 p r i n t f ( " \ n " ) ;

9 }

(11)

Teil IV: Anwendungen

Aufgabe 1: Definition einer geeigneten Datenstruktur

1. Aufgabenstellung

Definiere eine Datenstruktur f¨ur lineare Listen, in der jedes Element ein einzelnes Zeichen aufnehmen kann.

2. Kodierung

Aufgabe 2: Allokation eines neuen Elementes

1. Aufgabenstellung

Entwickle eine Funktion, die dynamisch ein neues Listenelement generiert.

2. Entwurf

Deklaration: neues Element alloziieren:

3. Kodierung

(12)

Aufgabe 3: Sortiertes Einf¨ ugen eines neuen Elementes

1. Aufgabenstellung

Nun wird’s ernst. Entwickle eine Funktion, die ein neues Element an der richtigen Stelle in die Liste einf¨ugt. Wir gehen wieder davon aus, dass die Elemente der Liste aufsteigend sortiert werden sollen.

2. Entwurf

Vervollst¨andige zun¨achst die Funktionsdeklaration:

Neues Element einf¨ugen:

3. Kodierung

(13)

Aufgabe 4: Ausgabe der Liste

1. Aufgabenstellung

Entwickle eine Funktion, die nacheinander alle Elemente einer ¨ubergebenen Liste ausgibt.

2. Entwurf

Vervollst¨andige zun¨achst die Funktionsdeklaration:

Liste ausgeben:

3. Kodierung

Aufgabe 5: Initialisierung der Liste

1. Aufgabenstellung

Jetzt fehlt noch die richtige Initialisierung einer neuen Liste. Im Skript haben wir gesehen, dass der konkrete Datenwert des Dummys unerheblich ist. Wichtig ist hin- gegen, dass der Next-Zeiger ein Null-Zeiger ist. Dies l¨asst sich einfach realisieren.

2. Kodierung

(14)

Aufgabe 6: Ein Hauptprogramm zum Testen

Den bereits erlernten argc/argv Mechanismus (siehe auch ¨Ubungspaket 25) k¨onnen wir hier sehr gut zum intelligenten Testen unseres Listen-Programms verwenden. Wenn wir auf diesen Mechanismus zur¨uckgreifen, brauchen wir nicht alles fest im Hauptprogramm zu kodieren und k¨onnen leicht und umfangreich testen.

1. Aufgabenstellung

Entwickle ein Hauptprogramm, mit dessen Hilfe wir unsere Listen-Funktionen in geeigneter Art und Weise testen k¨onnen. Mit Hilfe desargc/argv-Mechanismus soll das Hauptprogramm die folgenden Funktionalit¨aten anbieten:

1. Egal, wie wir unser Programm aufrufen, soll es die Liste direkt nach der Initia- lisierung sowie vor dem Programmende ausgeben.

2. Das erste Argument (argv[1]) soll alle Zeichen enthalten, die wir in die Liste aufnehmen. Beispiel: ./myListe vacation soll am Ende zu folgender Ausgabe f¨uhren: a a c i n o t v

3. Sollte noch ein zweites Argument (argv[2]) angegeben werden, dann soll die Liste nach jedem Einf¨ugen ausgegeben werden.

Mittels der bisherigen Vor¨ubungen, insbesondere ¨Ubungspaket 25, sollte die Umset- zung keine gr¨oßeren Schwierigkeiten bereiten.

2. Kodierung

Endlich fertig :-)

(15)

Aufgabe 7: Doppelt verkettete Listen

In dieser letzten ¨Ubungsaufgabe geht es um doppelt verkettete Listen. Die Bearbeitung ist vor allem theoretischer Natur, weshalb das Implementieren und Testen am Rechner freiwillig sind.

Wohin zeigen die Zeiger bei doppelt verketteten Listen?

Definiere eine Datenstruktur f¨ur ein Element einer doppelt verketteten Liste, die ein int und zwei double Variablen aufnehmen kann.

Skizziere an einem Beispiel, welche Zeiger beim Einf¨ugen eines neuen Elementes in eine bereits vorhandene Liste in welcher Form umgeh¨angt werden m¨ussen.

Referenzen

ÄHNLICHE DOKUMENTE

 Definition Konstruktormenge := mininale Menge von Operationen, mit denen man alle Elemente (=Instanzen) des ADT konstruieren kann..  Für Stack ist das die Menge

Implementieren Sie eine Zahlenmenge mit Hilfe einer linearen Liste (Hinweise: Ein Menge enthält niemals mehrere Exemplare der

Implementieren Sie eine doppelt verkettete Liste für Objekte in der Klasse LinkedList.. Die Schnittstelle ist durch die abstrakte Klasse List gegeben (für Methodenbeschreibungen

Datenstruktur Verkettete Liste von Schl¨ ussel/Werte-Paaren Suchen Elemente durchlaufen bis gefunden oder Listenende Einf¨ ugen Element in Liste.. Wert

struct dolili *elem_ptr = NULL; // Erzeugen eines Zeigers auf ein Element der Liste Damit Sie dynamisch neue Elemente einer Liste hinzufügen können, müssen Sie einen Teil des

Und dieses Prinzip soll auch noch funktionieren, wenn wir ein Programm haben, das ein paar Gigabyte Platz ben¨otigt und es tausende von freien Bl¨ocken gibt, die aber sehr klein

Alle zwei Jahre wird im Rah- men der ÖH-Wahlen auch auf der Fakultät für Maschi- nenbau die Studierendenver - tretung neu gewählt.. Wie bei den letzten Wahlen kandi- diert

• Gibt es verschiedene Klassen von Komponenten, die Ereignisse der gleichen Klasse erzeugen können, werden diese mit einem geeigneten Interface