Blatt01_WS11 - Universität Augsburg

Werbung
WS 2011/12
Fakultät Angewandte Informatik
Programmierung verteilter Systeme
17.10.2011
Prof. Dr. Bernhard Bauer
Übungen zur Vorlesung Informatik II, Blatt 1
Abgabe: Montag, 24.10.2011, 12.00 Uhr, Informatik II - Briefkasten und Programme zusätzlich per
Mail an den Tutor, bitte Namen und Matrikelnummer angeben.
In diesem Übungsblatt sollen die Möglichkeiten der Datenstrukturierung in der Programmiersprache C
aufgefrischt werden. In Java werden diese Möglichkeiten dann erweitert, so dass dies der perfekte
Einstieg in die Programmierung mit Java ist.
Es soll der Datentyp einer sogenannten doppelt verketteten Liste zur Verwaltung von Mengen ganzer
Zahlen betrachtet werden. Dieser ist wie folgt definiert:
typedef struct node {
int value;
struct node * next;
struct node * previous;
} NODE;
typedef struct list {
NODE * start;
int size;
} NATSET;
Ein Objekt vom Typ NATSET hat zwei Komponenten. Die Komponente start ist ein Zeiger auf einen
Knoten, nämlich den ersten Knoten der Liste. Der Wert der Komponente size entspricht immer der
Anzahl der Knoten der Liste. Jeder Knoten dient der Verwaltung einer ganzen Zahl durch die
Komponente value und hat in den Komponenten next und previous Zeiger auf den nächsten und
vorherigen Knoten der Liste. Damit hat also die Komponente previous des ersten Knotens der Liste
den Wert NULL, ebenso wie die Komponente next des letzten Knotens.
Eine Menge M ganzer Zahlen wird durch eine unsortierte Liste repräsentiert, die für jedes Element m
 M genau einen Knoten hat, dessen Komponente value den Wert m hat. Die leere Menge wird also
durch eine leere Liste repräsentiert.
Ziel ist es nun, einige Funktionen zu implementieren, die das Rechnen mit derart repräsentierten
Mengen erlauben, ohne die Datenstruktur zu kennen. Dabei ist entscheidend, dass die Funktionen
alle Datenstrukturinvarianten berücksichtigen. Die hier zu beachtenden Datenstrukturinvarianten
sollen im Folgenden noch einmal zusammengefasst aufgezählt werden:
- Der Wert der Komponente size entspricht der Anzahl der Knoten der Liste.
- Der Wert der Komponente value von zwei verschiedenen Knoten ist niemals gleich.
- Der Wert der Komponente previous des ersten Knotens ist NULL
- Der Wert der Komponente next des letzten Knotens ist NULL
Aus Gründen der Effizienz arbeiten wir natürlich nur mit Zeigern für die Parameterübergabe.
1
Aufgabe 1 *
Implementieren Sie die folgenden Funktionen:
int getSize (NATSET * pm)
Gibt den Wert der Komponente size von *pm zurück
NODE * getStart (NATSET * pm)
Gibt den Wert der Komponente start von *pm zurück
void setStart (NATSET * pm, NODE * l)
Setzt den Wert der Komponente start von *pm auf l
int getWert (NODE * k)
Gibt den Wert der Komponente value von *k zurück
void setWert (NODE * k, int m)
Setzt den Wert der Komponente value von *k auf m
NODE * getNext (NODE * k)
Gibt den Wert der Komponente next von *k zurück
void setNext (NODE * k, NODE * l)
Setzt den Wert der Komponente next von *k auf l
NODE * getPrevious (NODE * k)
Gibt den Wert der Komponente previous von *k zurück
void setPrevious (NODE * k, NODE * l)
Setzt den Wert der Komponente previous von *k auf l
Aufgabe 2 **
Implementieren Sie die folgenden Funktionen, wobei Sie bitte nicht mehr direkt auf die Komponenten
der Datenstrukturen NODE und NATSET zugreifen, falls dafür eine Funktion aus Aufgabe 1) zur
Verfügung steht:
int iselem (int m, NATSET * pm)
Soll 1 zurückgeben wenn m  *pm und 0 zurückgeben wenn m  *pm
void printset(NATSET * pm)
Gibt alle Elemente der Menge *pm in einer Zeile, jeweils durch ein Leerzeichen getrennt, in der
Kommandozeile aus.
NATSET * emptyset()
Reserviert dynamisch Speicherplatz für eine Variable vom Typ NATSET, initialisiert diese Variable als
die leere Menge und gibt einen Zeiger auf diese Variable zurück. Im Falle eines Fehlers soll NULL
zurückgegeben werden.
void destroy(NATSET *pm)
Zerstört die übergegeben Liste indem der dynamisch reservierte Speicherplatz wieder freigegeben
wird. Dazu muss insbesondere auch für alle Knoten der Liste der Speicherplatz freigegeben werden.
2
Aufgabe 3 ***
Implementieren Sie die folgenden Funktionen, wobei Sie bitte nicht mehr direkt auf die Komponenten
der Datenstrukturen NODE und NATSET zugreifen, falls dafür eine Funktion aus Aufgabe 1) zur
Verfügung steht:
int insert (int m, NATSET * pm)
Einfügen von m in *pm an der letzten Stelle, falls m noch nicht vorhanden ist. Dazu muss dynamisch
Speicherplatz für einen Knoten zur Repräsentation von m reserviert werden, der dann an letzter Stelle
der Liste angehängt wird. Soll -1 zurückgeben bei Auftreten eines Fehlers, sonst 0.
int delete (int m, NATSET * pm)
Löschen von m aus *pm. Soll -1 zurückgeben bei Nichtvorhandensein eines Knotens mit dem Wert m,
sonst 0. Es soll insbesondere der Speicherplatz des Knotens mit dem Wert m (so er vorhanden ist)
freigegeben werden.
Aufgabe 4 **
Testen Sie alle obigen Funktionen in einem Hauptprogramm. Benutzen Sie dazu nur obige Funktionen
und greifen Sie nicht direkt auf Komponenten der Datenstruktur zu!
Diskutieren Sie, wie ein Programmierer dummerweise Datenstruktur-Invarianten zerstören könnte,
indem er doch direkt auf Komponenten der Datenstrukturen zugreift.
3
Herunterladen