Institut für Informatik C-Kurs 09 Dynamische Datenstrukturen Dipl.-Inf. Jörn Hoffmann [email protected] Universität Leipzig Institut für Informatik Technische Informatik Flexible Datenstrukturen Institut für Informatik Dynamische Datenstrukturen • Strukturen, die zur Laufzeit angelegt werden • Skalierbar, Flexibel • Benötigen zusätzliche Verwaltungs- und Zugriffsoperationen Inhalt 1. Elementzugriff 2. Funktionszeiger 3. Lineare Listen 4. Bäume Jörn Hoffmann *(ptr).element ptr->element int (*ptr)(int); knoten->next; knoten->a | knoten->b; C-Kurs Folie 2 Zeiger Elementzugriff Institut für Informatik Syntax • *(Strukturzeiger).Komponenten; • Strukturzeiger -> Komponenten ; Semantik • Zugriff auf die Komponente einer struct bzw. union, auf die der Strukturzeiger verweist • Vereinfachung der Schreibweise der beiden Operationen 1. Zeiger Dereferenzierung 2. Komponentenzugriff Jörn Hoffmann C-Kurs Folie 3 Zeiger Elementzugriff Institut für Informatik Beispiel // zugriff.c typedef struct { char name[100]; int alter; } person_t; person_t pers = {“Max“, 25}; person_t *ptr = &pers; printf (“pers.name = %s, pers.alter = %d\n“, pers.name, pers.alter); printf (“ptr->name = %s, ptr->alter = %d\n“, ptr->name, ptr->alter); Jörn Hoffmann C-Kurs Folie 4 Funktionszeiger Institut für Informatik Syntax • Deklaration : Rückgabetyp (*Funktionszeigervariable)( Parameterliste ) • Zuweisung : Funktionszeigervariable = Funktionsname; • Aufruf : Funktionszeigervariable (Parameter); Semantik • Deklarieren einer Zeigervariablen, die auf eine Funktion mit dem angegebene Rückgabetypen und Parameterliste verweisen kann. • Zuweisen des Funktionszeigers einfach über Angabe des Funktionsnamens • Aufruf analog wie bei Funktion direkt Nutzen • Wiederverwendung einer Implementierung • Generische Programmierung Jörn Hoffmann C-Kurs Folie 5 Institut für Informatik Beispiel // funktionszeiger.c #include <stdio.h> void printZahl(int zahl) { printf("%d\n", zahl); } int main() { int (*ptr1) (const char*, ...) = printf; void (*ptr2)(int) = printZahl; ptr1("Hallo Welt\n"); // Aufruf (*ptr2)(2); // Aufruf (alternativ) return 0; } Jörn Hoffmann C-Kurs Folie 6 Flexible Datenstrukturen Zweck Institut für Informatik Anforderung • Programm zur Verwaltung von Kunden benötigt • Viele Kunden • Hohes Neuaufkommen von Kunden • Suche und Sortierung nötig Jörn Hoffmann C-Kurs Folie 7 Statisches Array Institut für Informatik 1. Lösung (Statisches Array) typedef struct { int knr; char *name; /* ... */ }kunde_t; // Statisches Array kunde_t kundendaten[10000]; Eigenschaften • Einfach • Speicherverschwendung • Keine flexible Verwaltung • Aufwändige Sortierung und Suche Jörn Hoffmann C-Kurs Folie 8 Dynamisches Array Institut für Informatik 2. Lösung (Dynamisches Array) typedef struct { int knr; char *name; /* ... */ }kunde_t; // Dynamisches Array (Halbstatisch) kunde_t *kundendaten = malloc(anzahlKunden * sizeof(kunde_t)); Eigenschaften • Bedarfsgerechte Speichernutzung • Aufwändiges Umkopieren bei neuen Kunden • Aufwändige Sortierung und Suche Jörn Hoffmann C-Kurs Folie 9 Lineare Liste Institut für Informatik 3. Lösung (Lineare Liste) typedef struct _knoten { kunde_t element; struct _knoten *next; } knoten_t; // Lineare Liste knoten_t *k1 = malloc(sizeof(knoten_t)); knoten_t *k2 = malloc(sizeof(knoten_t)); k1.next = k2; k2.next = NULL; Eigenschaften • Flexibel, Skalierbar • Geringer Mehraufwand durch indirekte Zeigerzugriffe Jörn Hoffmann C-Kurs Folie 10 Lineare Liste Institut für Informatik Lineare Liste • Dynamische Datenstruktur • Verwaltung von Elementen eines Typs • Verknüpft durch Zeiger • Kopf-Zeiger bestimmt aktuelle Einfügeposition • Letztes Element verweist auf NULL *kopf *(kopf.next) NULL kopf Jörn Hoffmann element next element C-Kurs next Folie 11 Lineare Liste Einfügen (Idee) Institut für Informatik Einfügen • Ermittlung des Einfügeplatzes • Änderung von zwei Verweisen (1) Vorgänger auf neues Element verweisen (2) Nachfolger im neuen Element setzen Neuer Knoten element next (1) (2) *kopf Listenende NULL kopf Jörn Hoffmann element next element C-Kurs next Folie 12 Lineare Liste Einfügen Institut für Informatik 0. Funktion Aufrufen • Funktion aufrufen • Parameter kopf zeigt auf Anfang der Liste • Parameter neuerKnoten wird fertig initialisiert übergeben • Element-Wert wird für Vergleiche benötig neu element next *kopf *next *next NULL ... kopf element Jörn Hoffmann next element next C-Kurs element next Folie 13 Lineare Liste Einfügen Institut für Informatik 1. Einfügeplatz finden • Liste mittels Schleife durchsuchen • Entscheidung ob aktueller Knoten durch Neuen ersetzen werden soll • Falls ja, Suche beenden • Falls nein, • Speicheradresse des Next-Zeigers in Hilfszeiger ablegen • Nächsten Knoten wählen neu hilf element *kopf next *next *next NULL ... kopf element Jörn Hoffmann next element next C-Kurs element next Folie 14 Lineare Liste Einfügen Institut für Informatik 2. Knoten einfügen • Wert des next-Zeigers vom neuen Knoten auf aktuellen Knoten setzen neu hilf element *kopf next *next, neu->next *next NULL ... kopf element Jörn Hoffmann next element next C-Kurs element next Folie 15 Lineare Liste Einfügen Institut für Informatik 3. Vorgänger anpassen • Next-Zeiger vom Vorgängerknoten auf neuen Knoten setzen • Dieser kann mittels Hilfszeiger direkt manipulieren werden neu hilf element *kopf next *next, neu->next *next NULL ... kopf element Jörn Hoffmann next element next C-Kurs element next Folie 16 Lineare Liste Einfügen Institut für Informatik 4. Liste anpassen • Kopf muss angepasst werden, falls es keinen Vorgänger gab • Kann ebenfalls über Hilfszeiger direkt manipuliert werden • Hilfszeiger muss am Anfang auf Kopf verweisen neu hilf element next neu->next *next NULL ... kopf Jörn Hoffmann element next C-Kurs element next Folie 17 Lineare Liste Einfügen Institut für Informatik 4. Fertig • Knoten ist jetzt eingefügt • Kopf wurde möglicherweise verändert *kopf *next *next NULL ... kopf element Jörn Hoffmann next element next C-Kurs element next Folie 18 Lineare Liste Beispiel Institut für Informatik void knotenEinfuegen(knoten_t **kopf, knoten_t *neuerKnoten) { knoten_t **hilf, *knoten; // Aktuellen Knoten auf Listenanfang setzen knoten = *kopf; hilf = kopf; // Finden der Einfügeposition while (knoten != NULL) { if(knoten->element > neuerKnoten->element) // Vergleich zur Entscheidung break; hilf = &knoten->next; // Adresse des Next-Zeiger speichern (kann direkt manipuliert werden) knoten = knoten->next; // Nächster Knoten } // Vorhandene Knoten an neuen Knoten anfügen neuerKnoten->next = knoten; // Vorgänger bzw. Kopf direkt anpassen *hilf = neuerKnoten; } Jörn Hoffmann C-Kurs Folie 19 Lineare Listen Typen Institut für Informatik Jörn Hoffmann C-Kurs Folie 20 Lineare Listen Typen Institut für Informatik C-Kurs Folie 21 Bäume Institut für Informatik Jörn Hoffmann C-Kurs Folie 22 Bäume Institut für Informatik Bäume • Wurzel • Ist Ausgezeichnetes Element (Zugriffspunkt) • Hat keine Vorgänger • Element • Hat genau ein Vorgänger • Hat beliebig viele Nachfolger • Blatt • ist Element ohne Nachfolger • Blätter können unterschiedliche Tiefe besitzen Jörn Hoffmann C-Kurs Folie 23 Bäume Binärbäume Institut für Informatik Binärbaum • Alle Elemente besitzen höchstens zwei Nachfolger • Viele Strategien zum Suchen, Einfügen, Entfernen von Elementen bekannt • Insb. um große Datenmengen schnell zu verarbeiten • Programmiertechnisch aufwendig Jörn Hoffmann C-Kurs Folie 24