Ein Doppel-Axel in C (2) lsearch, tsearch, hsearch

Größe: px
Ab Seite anzeigen:

Download "Ein Doppel-Axel in C (2) lsearch, tsearch, hsearch"

Transkript

1 Ein Doppel-Axel in C (2) lsearch, tsearch, hsearch Axel-Tobias Schreiner, Universität Ulm Kernighan und Ritchie s fünftes Kapitel 1 ist für jeden C Programmierer natürlich Pflicht. Die Kür besteht bei System V offensichtlich darin, Suchfunktionen nicht mehr selbst zu programmieren, sondern die verschiedenen Lösungen zu diesem Thema aus der Standard-Bücherei korrekt einsetzen zu können. In der letzten Ausgabe der Sprechstunde wurden Beispiele für die Verwendung der Funktionen qsor t() und bsearch() gezeigt; außerdem wurde die lsearch()-familie vorgestellt. Jetzt geht es mit dem üblichen Test weiter einem Programm zur Zählung der Häufigkeit von Worten in einem Text und wir betrachten auch noch die Funktionsfamilien hsearch() und tsearch(). Langsam zählen lsearch() und binary() lsearch() kann man zur Lösung des Häufigkeitsproblems höchstens als abschreckendes Beispiel verwenden. Als Kür für Zeiger eignet es sich aber ganz gut: typedef struct { char * word; int freq; Object; /* ein Wort */ 1...über Zeiger und Vektoren.

2 static Object * table; /* Vektor aller Worte */ static int t, mt; /* aktuelle und maximale Anzahl */ static int cmpw(a, b) register Object * a, * b; /* Worte vergleichen */ { return strcmp(a >word, b >word); static int cmpf(a, b) register Object * a, * b; /* Haeufigkeit vergleichen */ { register int c; return (c = a >freq b >freq)? c : strcmp(a >word, b >word); alpha() { register int i; Qsort(table, t, cmpw); for (i = 0; i < t; ++ i) puts(table[i].word); frequency() { register int i; Qsort(table, t, cmpf); for (i = 0; i < t; ++ i) puts(table[i].word); Da die Worte sicher verschieden lang sind, und da es wahrscheinlich ein paar sehr lange Worte gibt, speichern wir auch die Texte der Worte dynamisch. Die Tabelle mit den Zeigern auf die Worte und den Häufigkeitszählern wird selbstverständlich dynamisch unterhalten. lsearch() sortiert die Tabelle nicht; für die Ausgabe muß 2 deshalb die Tabelle jeweils nach dem richtigen Kriterium sortiert werden. Die 2 Qsor t() ist ein Makro aus der vorigen Ausgabe, der für die richtigen Umwandlungen bei qsor t() sorgt und die Elementgröße selbst berechnet.

3 ernsthafte Arbeit leistet count(), denn hier muß vor allem der Vektor table[] dynamisch verwaltet werden: count(word) register char * word; { char * malloc(), * realloc(); Object key, * kp; extern int inc; if (t == mt) if (! table) if (table = (Object *) malloc(inc * sizeof(object))) mt = inc; else fputs("no room\n", stderr), exit(1); else if (! (table = (Object *) realloc(table, (mt += inc) * sizeof(object)))) fputs("no more room\n", stderr), exit(1); t ist die aktuelle Länge der Tabelle, mt die verfügbare Länge. Sind t und mt gleich, ist in der Tabelle kein Platz (mehr) vorhanden. Gibt s dann noch keine Tabelle, wird sie mit malloc() angelegt, sonst wird sie mit realloc() verlängert und dabei unter Umständen intern umkopiert. inc können wir global beeinflussen es ist selbstverständlich, daß man den Tabellenplatz nicht nur um einzelne Elemente vergrößert. key.word = word; kp = lsearch(& key, table, & t, sizeof key, cmpw); if (kp >word == word) kp >word = strsave(word), kp >freq = 1; else ++ kp >freq;

4 Anschließend wird ein Tabellenelement key als Suchobjekt initialisiert und damit lsearch() bemüht. Der Trick besteht darin, das Wort selbst erst dann dynamisch zu speichern, wenn es wirklich neu ist, wenn also lsearch() wirklich key in die Tabelle kopiert hat und das Tabellenelement auf den Puffer zeigt, der an count() selbst übergeben wurde. strsave() findet man zum Beispiel im Abschnitt 5.6 bei Kernighan und Ritchie oder als strdup() bei XENIX. An Stelle von lsearch() kann man auch unsere Funktion binary() 3 aufrufen. In diesem Fall ist natürlich der Aufruf von qsor t() in alpha() unnötig. Hier sind ein paar Meßergebnisse: 3 Diese Funktion aus dem ersten Teil des Artikels sucht binär und fügt bei Bedarf ein Element so ein, daß die Tabelle sortiert bleibt.

5 count() user system Aktivität inc alpha() freqency() Summe heap Leerlauf lsearch() binary() Leerlauf lsearch() binary() lsearch() binary() Im ersten Teil der Tabelle wurde der SpreadSheet-Artikel aus der vorigen Ausgabe der unix/mail bearbeitet, im zweiten Teil nur die sortierte Liste der Worte, im dritten Teil die gleiche Liste, aber mit sor t -rin umgekehrter Reihenfolge. Man beobachtet natürlich, daß binary() wesentlich effizienter ist als lsearch(). Man sieht aber auch, daß 50 eine schlechte Wahl für inc war: malloc() fordert von sbrk() Speicher in größeren Stücken an; kleinere Schritte in der Tabellenvergrößerung wirken sich folglich ungünstig aus. Eine umgekehrt sortierte Liste von Worten ist der ungünstigste Fall für binary() trotzdem funktioniert die Funktion hier immer noch so gut wie lsearch()! Daß bei gleicher Eingabe im dritten Teil mehr dynamischer Speicherplatz als im zweiten Teil verbraucht wird, liegt an der Verteilung der Wortlängen; vergrößert man inc wieder auf 100, geht der Speicherplatzverbrauch

6 auch wieder zurück. Suchbäume tsearch() und twalk() In Programmiervorlesungen stellt man das Häufigkeitsproblem normalerweise als Aufgabe zu struct und dynamisch aufgebauten Datenstrukturen, nämlich zu binären Bäumen: typedef struct node Node; /* Knoten im Baum */ struct node { char * word; int freq; /* die Information */ Node * left, * right; /* die Unterbaeume */ ; In einer früheren Sprechstunde habe ich den üblichen iterativen Algorithmus gezeigt, mit dem man Worte so in einen binären Baum einträgt, daß er bei einer postorder- Traverse 4 sortiert erscheint. Inzwischen gibt es diesen Algorithmus als Büchereifunktion: #include <search.h> /* definiert VISIT */ char * tsearch(), * tfind(), * tdelete(); void twalk(); #define Tsearch(key, rootp, compar) \ 4 Nach Don Knuth s The Art of Computer Programming (Addison-Wesley 1968) unterscheidet man preorder (Wurzel vor Unterbäumen bearbeiten), postorder (Wurzel zwischen linkem und rechtem Unterbaum) und endorder (Wurzel nach Unterbäumen). In der zweiten Auflage wurde postorder zur sinnvolleren inorder, und endorder dann zu postorder. Bei System V glaubt man noch an die erste Auflage.

7 ((Object **) tsearch((char *) (key), /* gesuchtes Object */ \ (char **) (rootp), /* > > Wurzel */ \ (int (*)()) (compar))) /* Vergleichsfunktion */ #define Tfind(key, rootp, compar) \ ((Object **) tfind((char *) (key), /* gesuchtes Object */ \ (char **) (rootp), /* > > Wurzel */ \ (int (*)()) (compar))) /* Vergleichsfunktion */ #define Tdelete(key, rootp, compar) \ ((Object **) tdelete((char *) (key), /* gesuchtes Object */ \ (char **) (rootp), /* > > Wurzel */ \ (int (*)()) (compar))) /* Vergleichsfunktion */ #define Twalk(root, action) \ (twalk((char *) (root), /* > Wurzel */ \ (void (*)()) (action))) /* Aktion */ tfind() sucht Information in Form eines Zeigers(!) key in einem Suchbaum, auf dessen Wurzel ein Zeiger zeigen muß, dessen Adresse (Zeiger auf Zeiger!) als rootp übergeben wird. Der Suchbaum ist postorder-sortiert im Sinne der Vergleichsfunktion compar. Die Vergleichsfunktion erhält, wie bei den bisher betrachteten Suchoperationen, wieder zwei Zeiger des Typs, der als erstes Argument an tfind() geliefert wird. Als Resultat liefert tfind() bei Mißerfolg natürlich einen Nullzeiger, bei Erfolg aber einen Zeiger auf den Punkt im Suchbaum, bei dem die Information als Zeiger gespeichert ist, die compar als gleich zur Argument- Information betrachtet. Ein Unterschied zwischen lfind() und tfind() ist also, daß lfind() ein Resultat vom Typ des ersten Arguments liefert, tfind() aber einen Zeiger auf ein Datum mit dem Typ des ersten Arguments. tsearch() funktioniert wie tfind(), trägt aber bei Bedarf den als erstes Argument übergebenen Informationszeiger in den Suchbaum ein. tsearch() liefert einen Nullzeiger entweder, wenn als rootp ein Nullzeiger übergeben wird (das ist ein

8 Fehler), oder wenn kein dynamischer Speicherplatz zum Ausbau des Baums mehr vorhanden ist. tsearch() liefert einen Zeiger auf seinen ersten Argumentwert, wenn genau der Argumentwert im Baum gefunden oder gerade eingetragen wurde. Wir können also count() wieder implementieren: static int nel; /* Anzahl verschiedener Worte */ static char * root; /* Zeiger auf den Baum; NULL, also leer */ count(word) register char * word; { char * malloc(); register Object ** opp; Object key; key.word = word; if (! (opp = Tsearch(& key, & root, cmpw))) fputs("no tree room\n", stderr), exit(1); if (*opp == & key) { if (! (*opp = (Object *) malloc(sizeof(object)))) fputs("no node room\n", stderr), exit(1); (*opp) >word = strsave(word); (*opp) >freq = 1; ++ nel; else ++ (*opp) >freq; Object, strsave() und die Vergleichsfunktion cmpw() werden vom lsearch()-beispiel aus dem ersten Teil des Artikels übernommen. Wieder wird das Suchobjekt key initialisiert und damit tsearch() aufgerufen. Beim ersten Mal sollte ein leerer Baum als zweites Argument übergeben werden: root hat, als globale Variable, einen Nullzeiger als Anfangswert, und dessen Adresse repräsentiert dann einen leeren Baum.

9 tdelete() funktioniert ähnlich wie tfind(), das heißt, Information wird im Suchbaum lokalisiert. Anschließend verändert tdelete() den Suchbaum allerdings so, daß diese Information nicht mehr im Suchbaum steht: tdelete() löscht ein Element aus dem Suchbaum. Eine äquivalente Funktion gibt es bei den anderen Funktionsfamilien nicht. tdelete() ist jedoch keine glückliche Lösung um effizient einen ganzen Suchbaum zu löschen. Als Resultat liefert tdelete() bei Erfolg entweder einen Zeiger auf die Information im Vorgänger des gelöschten Elements im Suchbaum, einen Zeiger auf die Information im gerade gelöschten(!) Element, wenn es die Wurzel des Suchbaums war, oder einen Nullzeiger, wenn nichts gelöscht werden konnte. Dieser Aspekt von tdelete() ist nicht optimal überlegt. Gegenüber einer von lsearch() unterhaltenen Liste hat ein von tsearch() konstruierter Baum den Vorteil, daß er meistens effizienter durchsucht werden kann, und daß die Information im Baum auch in sortierter Reihenfolge erreichbar ist. Gegenüber unserer Funktion binary() sucht tsearch() meistens weniger effizient, muß aber dafür bei neuen Einträgen nichts verschieben. Baumtraversen realisiert die Funktion twalk(): für jedes Blatt im Suchbaum ruft sie eine vom Benutzer zu programmierende Funktion einmal auf, für jeden anderen Knoten dreimal. Die verschiedenen Argumente sind ein bißchen kompliziert: twalk() erhält direkt den Zeiger auf die Wurzel des Suchbaums ( ein Sternchen weniger als tsearch() ) und dazu die Benutzerfunktion. Die Benutzerfunktion erhält als erstes Argument einen Zeiger auf den Zeigerwert, der im Suchbaum eingetragen ist ( ein Sternchen mehr als die Vergleichsfunktion ) und der gerade besucht wird, als zweites Argument (C-Kür, Sie erinnern sich?) einen enum-wert, nämlich leaf, preorder, postorder oder endorder, und als drittes Argument das aktuelle Baumniveau. alpha() ist eine typische Anwendung von twalk(): static void visit(opp, order) register Object ** opp; VISIT order;

10 { switch (order) case leaf: case postorder: puts((*opp) >word); alpha() { twalk(root, visit); VISIT ist der enum-typ und stammt aus der öffentlichen Definitionsdatei search.h. visit() ist unsere Benutzerfunktion wir geben Worte alphabetisch aus, wenn wir Blätter oder Knoten in postorder erreichen. Hängt von switch() nur eine Anweisung ab, kann man ihr die case-marken voranstellen und auf die geschweiften Klammern verzichten. Für frequency(), die Ausgabe nach Häufigkeit, muß man umsortieren. Wir verwenden twalk() dazu, dynamisch einen Vektor von Zeigern auf unsere Object- Strukturen zu konstruieren. Den Vektor können wir dann mit qsor t() nach Häufigkeit sortieren und ausgeben: static int cmpf(a, b) register Object ** a, ** b; /* Vergleich */ { register int c; return (c = (*a) >freq (*b) >freq)? c : cmpw(*a, *b); static Object ** ptr; /* naechstes Vektorelement */ static void enter(opp, order) Object ** opp; VISIT order; /* baut Vektor */ { switch (order) case leaf: case endorder: *ptr++ = *opp;

11 frequency() { register Object ** table; register int i; char * malloc(); if (nel) { if (! (table = (Object **) malloc(nel * sizeof(object *)))) fputs("no room for index\n", stderr), exit(1); ptr = table; twalk(root, enter); Qsort(table, nel, cmpf); for (i = 0; i < nel; ++ i) puts(table[i] >word); free(table); Bei der Vergleichsfunktion cmpf() ist Vorsicht geboten: wir sortieren nicht mehr einen Vektor von Object-Strukturen sondern einen Vektor von Zeigern darauf. Da der Komponentenverweis -> Vorrang vor der Verweisoperation * hat, muß man wie oben klammern. Da die Werte der.freq-komponenten positiv sind, kann man die Differenz als Resultat des Vergleichs heranziehen. Es lohnt sich leider, dieses Beispiel auch noch auszuprobieren:

12 count() user system Eingabe alpha() freqency() Summe heap Artikel sortiert core dump sortiert* Artikel sortiert sort -r Vergleicht man mit der Tabelle zu lsearch() und binary() stellt man fest, daß tsearch() im Normalfall erheblich weniger Rechenzeit verbraucht dafür ist der Speicherverbrauch höher, denn irgendwo muß der Suchbaum schließlich stehen. Weniger schön ist die Reaktion, wenn die Worte sortiert eintreffen: der binäre Baum artet in eine lineare Liste aus und die Verfolgung von Zeigern ist dann noch geringfügig langsamer als das Absuchen eines Vektors. Der Zeitverlust ist nicht das einzige Problem. Bei einem normalen binären Baum muß twalk() rekursiv traversieren ein entarteter Baum verursacht dann entweder einen hohen Platzverbrauch auf dem Stack oder, wie hier bei XENIX den Prozeßabbruch. Mit einem bösartigen Trick kann man das Problem teilweise vermeiden: sortiert* bezieht sich auf einen Versuch, bei dem zuerst durch Eingabe von 52 Worten ein möglichst balancierter Baum gebildet wurde, zu dem dann erst die sortierte Liste der Worte aus dem Artikel hinzugefügt wurde. Die 52 Worte waren die Klein- und Großbuchstaben des Alphabets; die Balance des Baums wurde durch Verwendung des in einer früheren Spalte beschriebenen unsort-filters approximiert, der aus einer sortierten Eingabe einen Suchbaum minimaler Höhe bildet und ihn dann in preorder ausgibt, wodurch er bei der Eingabe zu tsearch() wieder mit minimaler Höhe

13 aufgebaut wird. Daß es auch anders geht, demonstriert der zweite Teil der Tabelle. Er beruht auf meiner Implementierung der tsearch()-funktionen mit Hilfe von binary threaded trees, 5 bei denen die Nullzeiger in den Blättern des Suchbaums so umfunktioniert werden, daß man preorder- und postorder-traverse iterativ ablaufen lassen kann. Für entartete Bäume funktionieren diese Funktionen etwas schlechter als binary(), aber als iterative Algorithmen vermeiden sie den hohen Platzverbrauch auf dem Stack mit seinen unangenehmen Konsequenzen. Klotzen malloc() Warum benötigt die Lösung mit binary threaded trees weniger dynamischen Speicherplatz? Wie im Kapitel 8 bei Kernighan und Ritchie nachzulesen ist, muß malloc() extern zu jeder vergebenen Speicherfläche Information aufbewahren, mit deren Hilfe free() später noch die Größe der Speicherfläche feststellen kann. Unsere Object-Struktur ist nicht sehr groß. Fordert man viele derart kleine Flächen an, die man ja in unserem Beispiel ohnehin nicht wieder freigibt, fällt die unsichtbare Information für free() stark gegenüber der nutzbaren Information in jedem Object ins Gewicht. Es ist also besser, wenn man bei count() nicht so sehr kleckert: count(word) register char * word; { char * malloc(); extern int inc; register Object ** opp; 5 Die Quellen sind zu lang für diese Spalte. Sie stehen im Kapitel 18 der Buchausgabe der UNIX Sprechstunde Hanser 1987 und auf der Diskette zu diesem Buch.

14 static Object * table; static int t; /* Speicherstueck */ if (! t &&! (table = (Object *) malloc((t = inc) * sizeof(object)))) fputs("no room\n", stderr), exit(1); table[ t].word = word; if (! (opp = Tsearch(& table[t], & root, cmpw))) fputs("no tree room\n", stderr), exit(1); if (*opp == & table[t]) ++ nel, (*opp) >word = strsave((*opp) >word), (*opp) >freq = 1; else ++ t; ++ (*opp) >freq; So holt man sich von malloc() Platz für inc Worte und gibt ihn dann mit absteigenden Indizes an den Suchbaum ab. Gibt man den Speicherplatz nicht mehr frei, kann man ihn auch direkt mit dem Systemaufruf sbrk() beim Systemkern 6 anfordern. Der Aufruf ist identisch zu malloc(). Es liegt zwar nahe, diese Funktion im Stil des lsearch()-beispiels so auszubauen, daß der Vektor table[] bei Bedarf mit realloc() verlängert wird, denn dann kann man sich den zusätzlich dynamisch angelegten Vektor für frequency() sparen, aber diese Lösung geht schief: Ist hinter der an realloc() übergebenen Fläche kein Platz mehr vorhanden, kopiert realloc() stillschweigend in eine neue, größere Fläche um. Die Zeiger auf die alte Fläche, die dann per tsearch() in unserem Suchbaum gespeichert sind, zeigen anschließend ins Leere und später in eine Gegend, die malloc() vermutlich neu vergeben hat! Man kann sich dadurch behelfen, daß man an Stelle 6 sbrk() wird in der System V Interface Definition nicht mehr erwähnt. Für malloc() gibt es eine neue Implementierung, bei der man kleine Blöcke bevorzugt behandeln lassen kann. Meine Versuche bei XENIX endeten allerdings mit einer Endlosschleife.

15 von Zeigern im Suchbaum Indexwerte in den Vektor table[] speichern läßt, denn diese Indexwerte ändern sich natürlich nicht, wenn realloc() den Vektor umkopiert: static Object * table; static int t, mt; static char * root; count(word) register char * word; { char * malloc(), * realloc(); extern int inc; register int * ip; if (t == mt) if (! table) if (table = (Object *) malloc(inc * sizeof(object))) mt = inc; else fputs("no room\n", stderr), exit(1); else if (! (table = (Object *) realloc(table, (mt += inc) * sizeof(object)))) fputs("no more room\n", stderr), exit(1); table[t].word = word, table[t].freq = 0; if (! (ip = (int *) Tsearch(t, & root, cmpw))) fputs("no tree room\n", stderr), exit(1); if (*ip == t) table[t].word = strsave(table[t].word), ++ t; ++ table[*ip].freq; static visit(ip, order) register int * ip; register VISIT order; { switch (order) case leaf: case postorder: puts(table[*ip].word);

16 int-werte kann man an Stelle von Zeigern übergeben, aber dadurch ändert sich natürlich die Interpretation des Resultattyps von tsearch(). Nach wie läßt alpha() durch twalk() den Baum traversieren, aber auch bei visit() taucht jetzt ein anderer Typ aus dem Suchbaum auf wie immer der gleiche, den tsearch() als Resultat liefert, und damit ein Sternchen mehr als das erste Argument von tsearch(). Die Funktion frequency() befaßt sich mit dem Vektor table[] und wurde deshalb schon im lsearch()-beispiel gezeigt. Raten hsearch() Wenn man zum Beispiel nur die 26 Buchstaben des Alphabets unterscheiden muß, wird man kaum einen Suchbaum bemühen. Für kleine Wertemengen stellt man einen Vektor zur Verfügung und berechnet die Indexwerte mit einer Funktion, die einen Wert einem Vektorelement zuordnet. Auf dieser Idee beruhen die sogenannten Hash-Verfahren, bei denen ein Vektor fixer Länge als Tabelle verwendet wird. Eine Hash-Funktion berechnet aus dem Suchschlüssel einen Index in die Tabelle, und so wird zunächst überhaupt keine Vergleichsoperation benötigt. Da jedoch viele mögliche Suchschlüssel (bei uns alle vorstellbaren Worte) wenigen Tabellenplätzen gegenüberstehen, kann die Hash- Funktion nicht eindeutig sein, und man muß den Suchschlüssel wenigstens mit einem Tabelleneintrag vergleichen. Streut die Hash-Funktion sehr gut, bleibt s bei dem einen Vergleich und das Verfahren ist jeder anderen Methode überlegen. Bildet die Hash-Funktion mehrere tatsächlich verwendete Suchschlüssel auf den gleichen Tabelleneintrag ab, muß man einen Algorithmus zur Auflösung der Kollisionen verwenden. Dieser Algorithmus hat oft zur Folge, daß aus einer Hash-Tabelle keine Einträge gelöscht werden können die Tabelle muß also größer angelegt werden,

17 als die maximal erwartete Anzahl von Einträgen, denn die Auflösung von Kollisionen wird natürlich schwieriger, wenn die Tabelle fast voll ist. hsearch() implementiert ein Hash-Verfahren. Im Gegensatz zu allen anderen Suchfunktionen kann hsearch() jedoch nur eine einzige, unsichtbare Tabelle manipulieren. Sie wird mit hcreate() erzeugt dabei legt man ihre Größe fest und sie kann mit hdestroy() insgesamt zerstört werden. hsearch() folgt völlig anderen Konventionen als die anderen Suchfunktionen: das erste Argument ist eine Struktur(!) vom Typ ENTRY, der in der öffentlichen Definitionsdatei search.h vereinbart wird; das zweite Argument ist der enum-wert FIND, wenn nur gesucht werden soll, oder ENTER, wenn bei Bedarf auch eingetragen werden soll. Auch diese Werte sind in search.h definiert. ENTRY hat eine erste Komponente.key, die auf den String zeigt, der als Suchschlüssel verwendet werden soll. Die zweite Komponente.data ist ein (beliebiger) Zeiger. hsearch() liefert als Resultat einen Zeiger auf einen ENTRY in der Hash-Tabelle (also auf eine Kopie des ersten Arguments) und im Fehlerfall einen Nullzeiger, wenn es bei FIND keinen entsprechenden Eintrag gibt, oder wenn bei ENTER die Tabelle voll ist. Da die Hash-Tabelle von hsearch() verborgen wird und ohnehin nicht sortiert ist, müssen wir diesmal alle Worte selbst noch auffädeln: #include <search.h> typedef struct { /* unsere Information fuer.data */ ENTRY * next; /* lineare Liste der Worte */ int freq; /* Haeufigkeit */ Data; /* Zugriffsmakros */ #define Ekey(ep) ((ep) > key) /* Wort */ #define Edata(ep) ((Data *) (ep) > data) /* Information */ #define Efreq(ep) (Edata(ep) > freq) /* Haeufigkeit */

18 #define Enext(ep) (Edata(ep) > next) /* lineare Liste */ static int nel; /* Anzahl Worte */ static ENTRY * list; /* lineare Liste */ Mit Zugriffsmakros kann man allzu schlimme Zeigerausdrücke vermeiden. Sie werden für jede interessante Komponente einmal formuliert, hängen zweckmäßigerweise von einem Zeiger auf ein Element der Hash-Tabelle ab, und sind nebeneffektfrei und als L-Werte formuliert, damit man sie in jedem Kontext verwenden kann. count() legt beim ersten Aufruf eine Hash-Tabelle mit inc Einträgen an: count(word) register char * word; { char * malloc(); ENTRY item, * ep, * hsearch(); static Data data; extern int inc; if (! list &&! hcreate(inc)) fputs("no hash room\n", stderr), exit(1); Ekey(& item) = word, Edata(& item) = & data; Anschließend wird das Suchobjekt gebildet. data ist static definiert und hat damit eine.freq-komponente mit Wert 0. Jetzt können wir hsearch() bemühen: if (! (ep = hsearch(item, ENTER))) fputs("no more hash room\n", stderr), exit(1); if (! Efreq(ep)) { if (! (Edata(ep) = (Data *) malloc(sizeof(data)))) fputs("no data room\n", stderr), exit(1); Ekey(ep) = strsave(word), Efreq(ep) = 1; Enext(ep) = list, list = ep; ++ nel;

19 else ++ Efreq(ep); Ist dann die.freq-komponente immer noch 0, wurde unser Suchobjekt gerade kopiert, das heißt, in der Hash-Tabelle stehen jetzt Zeiger auf unser word (auf unserem Stack!) und auf unsere Struktur data. Wir speichern deshalb das Wort dynamisch, legen die Information data dynamisch an, verketten mit unserer Liste und initialisieren den Häufigkeitszähler. Auch hier sollte man malloc() entlasten und größere Blöcke auf einmal anfordern. alpha(), frequency() und die zum Sortieren nötigen Vergleichsfunktionen sind Variationen zu einem bekannten Thema wenn man unsere Zugriffsmakros verwendet: static int cmpw(a, b) register ENTRY ** a, ** b; { return strcmp(ekey(*a), Ekey(*b)); alpha() { visit(cmpw); static int cmpf(a, b) register ENTRY ** a, ** b; { register int c; return (c = Efreq(*a) Efreq(*b))? c : cmpw(a, b); frequency() { visit(cmpf);

20 visit() leistet in beiden Fällen die gleiche Arbeit: für die lineare Liste muß ein Vektor mit Zeigern angelegt werden, der dann per qsor t() sortiert und ausgegeben werden kann. Man könnte auch wieder in count() mit realloc() einen Vektor dynamisch vergrößern und in der Hash-Tabelle als.data nur Indexwerte speichern, aber die vorliegende Lösung ist vermutlich klarer: static visit(cmp) int (* cmp)(); { register ENTRY ** table, ** tp, * ep; register int i; char * malloc(); if (nel) { if (! (table = (ENTRY **) malloc(nel * sizeof(entry *)))) fputs("no room for index\n", stderr), exit(1); for (ep = list, tp = table; ep; ep = Enext(ep)) *tp++ = ep; Qsort(table, nel, cmp); for (i = 0; i < nel; ++ i) puts(ekey(table[i])); free(table); Wie gut das Hash-Verfahren funktioniert, zeigt folgende Tabelle:

21 count() user system inc Eingabe alpha() freqency() Summe heap 966 Artikel sortiert Artikel sortiert Artikel sortiert Man sieht, daß das Hash-Verfahren selbst besser funktioniert als der Einsatz von Suchbäumen. Muß man sortiert ausgeben, benötigen bei unserem Beispiel beide Methoden insgesamt gleich viel Zeit und Speicherplatz. Das Hash-Verfahren ist vielleicht etwas komplizierter zu codieren, hat dafür aber den Vorteil, daß es auch bei sortierter Eingabe nicht zusammenbricht. Sehr wesentlich ist, daß das Verfahren auch dann nahezu gleich schnell abläuft, wenn die Tabelle mit 966 Worten 7 vollständig gefüllt wird. 7 Fordert man mit hcreate() genau 966 Tabelleneinträge an, kann man 1023 Worte speichern hcreate() macht die Tabelle möglicherweise etwas größer, damit die Hash-Methode korrekt funktioniert. Füllt man die Tabelle wirklich ganz, ändert sich das Zeitverhalten kaum.

22 Zusammenfassung Ist jetzt die richtige Wahl so schwer, daß man die nächste Suchoperation doch wieder selber programmiert? Ich glaube nicht. Beim Schreiben dieses Artikels habe ich mir vor allem die Aufrufkonventionen aller Funktionen klar gemacht, und in Zukunft würde ich folgendermaßen vorgehen: hsearch() ist allen anderen Methoden überlegen, falls man nicht (viele) Elemente wieder löschen muß, oder den Platzbedarf überhaupt nicht voraussehen kann, oder falls man nicht (oft) im Währenden sortiert ausgeben muß. lsearch() hat meines Erachtens keine mildernden Umstände. Für binary() spricht dagegen eine wesentlich verbesserte Effizienz sowie die Möglichkeit, daß man jederzeit garantiert neue und/oder sortierte Information zur Tabelle insgesamt hinzufügen und die Tabelle dann mit qsor t() für binary() wieder verwendbar machen kann. binary() würde ich verwenden, wenn ich den Platzbedarf nicht kenne, viel suchen und wenig neu eintragen muß, und vor allem, wenn häufig aber nicht vorhersehbar mit sortierter Information zu rechnen ist. tsearch() funktioniert so gut wie hsearch(), wenn sortiert ausgegeben werden muß, und wenn die angebotene Information nicht entartet. Bei hsearch() muß ein String als Suchschlüssel verwendet werden, bei tsearch() liefert man die Vergleichsfunktion selbst. Bäume können beliebig wachsen, Hash-Tabellen nicht, und die Probleme bei sortierter Information habe ich in meiner Implementierung entschärft.

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen Binäre Bäume 1. Allgemeines Binäre Bäume werden grundsätzlich verwendet, um Zahlen der Größe nach, oder Wörter dem Alphabet nach zu sortieren. Dem einfacheren Verständnis zu Liebe werde ich mich hier besonders

Mehr

Bäume. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 10: Collections 4. Inhalt. Bäume. Einführung. Bäume.

Bäume. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 10: Collections 4. Inhalt. Bäume. Einführung. Bäume. Universität Osnabrück 1 Bäume 3 - Objektorientierte Programmierung in Java Vorlesung 10: Collections 4 Einführung Bäume sind verallgemeinerte Listenstrukturen Lineare Liste Jedes Element hat höchstens

Mehr

Grundlagen der Informatik. Prof. Dr. Stefan Enderle NTA Isny

Grundlagen der Informatik. Prof. Dr. Stefan Enderle NTA Isny Grundlagen der Informatik Prof. Dr. Stefan Enderle NTA Isny 2 Datenstrukturen 2.1 Einführung Syntax: Definition einer formalen Grammatik, um Regeln einer formalen Sprache (Programmiersprache) festzulegen.

Mehr

Folge 19 - Bäume. 19.1 Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Folge 19 - Bäume. 19.1 Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12 Grundlagen: Folge 19 - Bäume 19.1 Binärbäume - Allgemeines Unter Bäumen versteht man in der Informatik Datenstrukturen, bei denen jedes Element mindestens zwei Nachfolger hat. Bereits in der Folge 17 haben

Mehr

368 4 Algorithmen und Datenstrukturen

368 4 Algorithmen und Datenstrukturen Kap04.fm Seite 368 Dienstag, 7. September 2010 1:51 13 368 4 Algorithmen und Datenstrukturen Java-Klassen Die ist die Klasse Object, ein Pfeil von Klasse A nach Klasse B bedeutet Bextends A, d.h. B ist

Mehr

Kapiteltests zum Leitprogramm Binäre Suchbäume

Kapiteltests zum Leitprogramm Binäre Suchbäume Kapiteltests zum Leitprogramm Binäre Suchbäume Björn Steffen Timur Erdag überarbeitet von Christina Class Binäre Suchbäume Kapiteltests für das ETH-Leitprogramm Adressaten und Institutionen Das Leitprogramm

Mehr

13. Binäre Suchbäume

13. Binäre Suchbäume 1. Binäre Suchbäume Binäre Suchbäume realiesieren Wörterbücher. Sie unterstützen die Operationen 1. Einfügen (Insert) 2. Entfernen (Delete). Suchen (Search) 4. Maximum/Minimum-Suche 5. Vorgänger (Predecessor),

Mehr

4. Jeder Knoten hat höchstens zwei Kinder, ein linkes und ein rechtes.

4. Jeder Knoten hat höchstens zwei Kinder, ein linkes und ein rechtes. Binäre Bäume Definition: Ein binärer Baum T besteht aus einer Menge von Knoten, die durch eine Vater-Kind-Beziehung wie folgt strukturiert ist: 1. Es gibt genau einen hervorgehobenen Knoten r T, die Wurzel

Mehr

Algorithmen und Datenstrukturen Suchbaum

Algorithmen und Datenstrukturen Suchbaum Algorithmen und Datenstrukturen Suchbaum Matthias Teschner Graphische Datenverarbeitung Institut für Informatik Universität Freiburg SS 12 Motivation Datenstruktur zur Repräsentation dynamischer Mengen

Mehr

Der linke Teilbaum von v enthält nur Schlüssel < key(v) und der rechte Teilbaum enthält nur Schlüssel > key(v)

Der linke Teilbaum von v enthält nur Schlüssel < key(v) und der rechte Teilbaum enthält nur Schlüssel > key(v) Ein Baum T mit Knotengraden 2, dessen Knoten Schlüssel aus einer total geordneten Menge speichern, ist ein binärer Suchbaum (BST), wenn für jeden inneren Knoten v von T die Suchbaumeigenschaft gilt: Der

Mehr

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen Dipl. Inform. Andreas Wilkens aw@awilkens.com Überblick Grundlagen Definitionen Elementare Datenstrukturen Rekursionen Bäume 2 1 Datenstruktur Baum Definition eines Baumes

Mehr

Lernziele: Ausgleichstechniken für binäre Bäume verstehen und einsetzen können.

Lernziele: Ausgleichstechniken für binäre Bäume verstehen und einsetzen können. 6. Bäume Lernziele 6. Bäume Lernziele: Definition und Eigenschaften binärer Bäume kennen, Traversierungsalgorithmen für binäre Bäume implementieren können, die Bedeutung von Suchbäumen für die effiziente

Mehr

Idee: Wenn wir beim Kopfknoten zwei Referenzen verfolgen können, sind die Teillisten kürzer. kopf Eine Datenstruktur mit Schlüsselwerten 1 bis 10

Idee: Wenn wir beim Kopfknoten zwei Referenzen verfolgen können, sind die Teillisten kürzer. kopf Eine Datenstruktur mit Schlüsselwerten 1 bis 10 Binäre Bäume Bäume gehören zu den wichtigsten Datenstrukturen in der Informatik. Sie repräsentieren z.b. die Struktur eines arithmetischen Terms oder die Struktur eines Buchs. Bäume beschreiben Organisationshierarchien

Mehr

Algorithmen und Datenstrukturen SS09

Algorithmen und Datenstrukturen SS09 Foliensatz 8 Michael Brinkmeier Technische Universität Ilmenau Institut für Theoretische Informatik Sommersemester 29 TU Ilmenau Seite / 54 Binärbäume TU Ilmenau Seite 2 / 54 Binäre Bäume Bäume und speziell

Mehr

Binäre Bäume Darstellung und Traversierung

Binäre Bäume Darstellung und Traversierung Binäre Bäume Darstellung und Traversierung Name Frank Bollwig Matrikel-Nr. 2770085 E-Mail fb641378@inf.tu-dresden.de Datum 15. November 2001 0. Vorbemerkungen... 3 1. Terminologie binärer Bäume... 4 2.

Mehr

Programmiertechnik II

Programmiertechnik II Bäume Symboltabellen Suche nach Werten (items), die unter einem Schlüssel (key) gefunden werden können Bankkonten: Schlüssel ist Kontonummer Flugreservierung: Schlüssel ist Flugnummer, Reservierungsnummer,...

Mehr

Wiederholung ADT Menge Ziel: Verwaltung (Finden, Einfügen, Entfernen) einer Menge von Elementen

Wiederholung ADT Menge Ziel: Verwaltung (Finden, Einfügen, Entfernen) einer Menge von Elementen Was bisher geschah abstrakter Datentyp : Signatur Σ und Axiome Φ z.b. ADT Menge zur Verwaltung (Finden, Einfügen, Entfernen) mehrerer Elemente desselben Typs Spezifikation einer Schnittstelle Konkreter

Mehr

Datenstrukturen & Algorithmen

Datenstrukturen & Algorithmen Datenstrukturen & Algorithmen Matthias Zwicker Universität Bern Frühling 2010 Übersicht Binäre Suchbäume Einführung und Begriffe Binäre Suchbäume 2 Binäre Suchbäume Datenstruktur für dynamische Mengen

Mehr

Kap. 4.2: Binäre Suchbäume

Kap. 4.2: Binäre Suchbäume Kap. 4.2: Binäre Suchbäume Professor Dr. Lehrstuhl für Algorithm Engineering, LS11 Fakultät für Informatik, TU Dortmund 11. VO DAP2 SS 2009 26. Mai 2009 1 Zusätzliche Lernraumbetreuung Morteza Monemizadeh:

Mehr

Fakultät Angewandte Informatik Lehrprofessur für Informatik 23.01.2012

Fakultät Angewandte Informatik Lehrprofessur für Informatik 23.01.2012 WS 2011/2012 Fakultät Angewandte Informatik Lehrprofessur für Informatik 23.01.2012 Prof. Dr. Robert Lorenz Musterlösung zur Vorlesung Informatik I, Extrablatt zu komplexen Datenstrukturen Aufgabe 45 **

Mehr

Informatik II Bäume. Beispiele. G. Zachmann Clausthal University, Germany zach@in.tu-clausthal.de. Stammbaum. Stammbaum. Stammbaum

Informatik II Bäume. Beispiele. G. Zachmann Clausthal University, Germany zach@in.tu-clausthal.de. Stammbaum. Stammbaum. Stammbaum lausthal Beispiele Stammbaum Informatik II. Zachmann lausthal University, ermany zach@in.tu-clausthal.de. Zachmann Informatik - SS 06 Stammbaum Stammbaum / Parse tree, Rekursionsbaum Parse tree, Rekursionsbaum

Mehr

Eine Baumstruktur sei folgendermaßen definiert. Eine Baumstruktur mit Grundtyp Element ist entweder

Eine Baumstruktur sei folgendermaßen definiert. Eine Baumstruktur mit Grundtyp Element ist entweder Programmieren in PASCAL Bäume 1 1. Baumstrukturen Eine Baumstruktur sei folgendermaßen definiert. Eine Baumstruktur mit Grundtyp Element ist entweder 1. die leere Struktur oder 2. ein Knoten vom Typ Element

Mehr

3.2 Binäre Suche. Usr/local/www/ifi/fk/menschen/schmid/folien/infovk.ppt 1

3.2 Binäre Suche. Usr/local/www/ifi/fk/menschen/schmid/folien/infovk.ppt 1 3.2 Binäre Suche Beispiel 6.5.1: Intervallschachtelung (oder binäre Suche) (Hier ist n die Anzahl der Elemente im Feld!) Ein Feld A: array (1..n) of Integer sei gegeben. Das Feld sei sortiert, d.h.: A(i)

Mehr

1. Einfach verkettete Liste unsortiert 2. Einfach verkettete Liste sortiert 3. Doppelt verkettete Liste sortiert

1. Einfach verkettete Liste unsortiert 2. Einfach verkettete Liste sortiert 3. Doppelt verkettete Liste sortiert Inhalt Einführung 1. Arrays 1. Array unsortiert 2. Array sortiert 3. Heap 2. Listen 1. Einfach verkettete Liste unsortiert 2. Einfach verkettete Liste sortiert 3. Doppelt verkettete Liste sortiert 3. Bäume

Mehr

Zeichnen von Graphen. graph drawing

Zeichnen von Graphen. graph drawing Zeichnen von Graphen graph drawing WS 2006 / 2007 Gruppe: D_rot_Ala0607 Christian Becker 11042315 Eugen Plischke 11042351 Vadim Filippov 11042026 Gegeben sei ein Graph G = (V; E) Problemstellung V E =

Mehr

Datenstrukturen und Algorithmen

Datenstrukturen und Algorithmen Datenstrukturen und Algorithmen VO 708.031 Bäume robert.legenstein@igi.tugraz.at 1 Inhalt der Vorlesung 1. Motivation, Einführung, Grundlagen 2. Algorithmische Grundprinzipien 3. Sortierverfahren 4. Halden

Mehr

Suchen in Listen und Hashtabellen

Suchen in Listen und Hashtabellen Kapitel 12: Suchen in Listen und Hashtabellen Einführung in die Informatik Wintersemester 2007/08 Prof. Bernhard Jung Übersicht Einleitung Lineare Suche Binäre Suche (in sortierten Listen) Hashverfahren

Mehr

Programmieren in C. Operatoren, Variablen und deren Sichtbarkeit. Prof. Dr. Nikolaus Wulff

Programmieren in C. Operatoren, Variablen und deren Sichtbarkeit. Prof. Dr. Nikolaus Wulff Programmieren in C Operatoren, Variablen und deren Sichtbarkeit Prof. Dr. Nikolaus Wulff Auswertung von Ausdrücken Was passiert wenn ein Ausdruck wie z. B. int y,x=2; y = ++x * x++; im Computer abgearbeitet

Mehr

Datenstruktur, die viele Operationen dynamischer Mengen unterstützt

Datenstruktur, die viele Operationen dynamischer Mengen unterstützt Algorithmen und Datenstrukturen 265 10 Binäre Suchbäume Suchbäume Datenstruktur, die viele Operationen dynamischer Mengen unterstützt Kann als Wörterbuch, aber auch zu mehr eingesetzt werden (Prioritätsschlange)

Mehr

182. stdio. 183. stdio. Eingabe. Ausgabe. Typisch für Zeileneingabe und Analyse: #include

182. stdio. 183. stdio. Eingabe. Ausgabe. Typisch für Zeileneingabe und Analyse: #include <stdio.h> 182. stdio Eingabe int getchar (), getc (FILE * fp), fgetc (FILE * fp); char * gets (char * buf), * fgets (char * buf, int len, FILE * fp); int scanf (const char * fmt,...); int fscanf (FILE * fp, const

Mehr

9.4 Binäre Suchbäume. Xiaoyi Jiang Informatik II Datenstrukturen und Algorithmen

9.4 Binäre Suchbäume. Xiaoyi Jiang Informatik II Datenstrukturen und Algorithmen 9.4 Binäre Suchbäume Erweiterung: Einfügen an der Wurzel Standardimplementierung: Der neue Schlüssel wird am Ende des Suchpfades angefügt (natürlich, weil zuerst festgestellt werden muss, ob der Schlüssel

Mehr

Tutorium Algorithmen & Datenstrukturen

Tutorium Algorithmen & Datenstrukturen June 16, 2010 Binärer Baum Binärer Baum enthält keine Knoten (NIL) besteht aus drei disjunkten Knotenmengen: einem Wurzelknoten, einem binären Baum als linken Unterbaum und einem binären Baum als rechten

Mehr

Suchen und Sortieren

Suchen und Sortieren (Folie 69, Seite 36 im Skript) 5 6 1 4 Als assoziatives Array geeignet Schlüssel aus geordneter Menge Linke Kinder kleiner, rechte Kinder größer als Elternknoten Externe und interne Knoten Externe Knoten

Mehr

Vorname:... Matrikel-Nr.:... Unterschrift:...

Vorname:... Matrikel-Nr.:... Unterschrift:... Fachhochschule Mannheim Hochschule für Technik und Gestaltung Fachbereich Informatik Studiengang Bachelor of Computer Science Algorithmen und Datenstrukturen Wintersemester 2003 / 2004 Name:... Vorname:...

Mehr

Branch-and-Bound. Wir betrachten allgemein Probleme, deren Suchraum durch Bäume dargestellt werden kann. Innerhalb des Suchraums suchen wir

Branch-and-Bound. Wir betrachten allgemein Probleme, deren Suchraum durch Bäume dargestellt werden kann. Innerhalb des Suchraums suchen wir Effiziente Algorithmen Lösen NP-vollständiger Probleme 289 Branch-and-Bound Wir betrachten allgemein Probleme, deren Suchraum durch Bäume dargestellt werden kann. Innerhalb des Suchraums suchen wir 1.

Mehr

Was bisher geschah. deklarative Programmierung. funktionale Programmierung (Haskell):

Was bisher geschah. deklarative Programmierung. funktionale Programmierung (Haskell): Was bisher geschah deklarative Programmierung funktional: Programm: Menge von Termgleichungen, Term Auswertung: Pattern matsching, Termumformungen logisch: Programm: Menge von Regeln (Horn-Formeln), Formel

Mehr

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12. Kapitel 13. Bäume. Bäume

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12. Kapitel 13. Bäume. Bäume 1 Kapitel 13 Ziele 2 Den Begriff des Baums in der Informatik kennenlernen als verkettete Datenstruktur repräsentieren können Rekursive Funktionen auf n verstehen und schreiben können Verschiedene Möglichkeiten

Mehr

Beispiel zu Datenstrukturen

Beispiel zu Datenstrukturen zu Datenstrukturen Passend zum Kurs 01661 Version Juni 2008 Dieter Hoffmann Dipl.-Inform. Diese Kurshilfe zum Kurs Datenstrukuren I (Kursnummer 01661) bei Prof. Dr. Güting (Lehrgebiet Praktische Informatik

Mehr

Einführung in die Programmierung Konstanten, dynamische Datenstrukturen. Arvid Terzibaschian

Einführung in die Programmierung Konstanten, dynamische Datenstrukturen. Arvid Terzibaschian Einführung in die Programmierung Arvid Terzibaschian 1 Konstanten 2 Motivation Unveränderliche, wichtige Werte mathematische Konstanten z.b. PI String-Konstanten wie z.b. häufige statische Meldungen mögliche

Mehr

Arbeiten mit Arrays. 4.1 Eigenschaften. 4.1.1 Schlüssel und Element. Kapitel 4

Arbeiten mit Arrays. 4.1 Eigenschaften. 4.1.1 Schlüssel und Element. Kapitel 4 Arbeiten mit s Eine effiziente Programmierung mit PHP ohne seine s ist kaum vorstellbar. Diese Datenstruktur muss man verstanden haben, sonst brauchen wir mit weitergehenden Programmiertechniken wie der

Mehr

Übung 9. Quellcode Strukturieren Rekursive Datenstrukturen Uebung 9

Übung 9. Quellcode Strukturieren Rekursive Datenstrukturen Uebung 9 Informatik I 2 Übung 9 Quellcode Strukturieren Rekursive Datenstrukturen Uebung 9 Quellcode Strukturieren Wenn alle Funktionen in einer Datei zusammengefasst sind wird es schnell unübersichtlich Mehrere

Mehr

Objektorientiertes Programmieren für Ingenieure

Objektorientiertes Programmieren für Ingenieure Uwe Probst Objektorientiertes Programmieren für Ingenieure Anwendungen und Beispiele in C++ 18 2 Von C zu C++ 2.2.2 Referenzen und Funktionen Referenzen als Funktionsparameter Liefert eine Funktion einen

Mehr

C++ Grundlagen. ++ bedeutet Erweiterung zum Ansi C Standard. Hier wird eine Funktion eingeleitet

C++ Grundlagen. ++ bedeutet Erweiterung zum Ansi C Standard. Hier wird eine Funktion eingeleitet C++ Grundlagen ++ bedeutet Erweiterung zum Ansi C Standard Hier wird eine Funktion eingeleitet Aufbau: In dieser Datei stehen die Befehle, die gestartet werden, wenn das Programm gestartet wird Int main()

Mehr

Codierungstheorie Rudolf Scharlau, SoSe 2006 9

Codierungstheorie Rudolf Scharlau, SoSe 2006 9 Codierungstheorie Rudolf Scharlau, SoSe 2006 9 2 Optimale Codes Optimalität bezieht sich auf eine gegebene Quelle, d.h. eine Wahrscheinlichkeitsverteilung auf den Symbolen s 1,..., s q des Quellalphabets

Mehr

DATENSTRUKTUREN UND ZAHLENSYSTEME

DATENSTRUKTUREN UND ZAHLENSYSTEME DATENSTRUKTUREN UND ZAHLENSYSTEME RALF HINZE Institute of Information and Computing Sciences Utrecht University Email: ralf@cs.uu.nl Homepage: http://www.cs.uu.nl/~ralf/ March, 2001 (Die Folien finden

Mehr

Erwin Grüner 15.12.2005

Erwin Grüner 15.12.2005 FB Psychologie Uni Marburg 15.12.2005 Themenübersicht Mit Hilfe der Funktionen runif(), rnorm() usw. kann man (Pseudo-) erzeugen. Darüber hinaus gibt es in R noch zwei weitere interessante Zufallsfunktionen:

Mehr

Vorlesung 04.12.2006: Binäre Entscheidungsdiagramme (BDDs) Dr. Carsten Sinz

Vorlesung 04.12.2006: Binäre Entscheidungsdiagramme (BDDs) Dr. Carsten Sinz Vorlesung 04.12.2006: Binäre Entscheidungsdiagramme (BDDs) Dr. Carsten Sinz Datenstruktur BDD 1986 von R. Bryant vorgeschlagen zur Darstellung von aussagenlogischen Formeln (genauer: Booleschen Funktionen)

Mehr

2 Java: Bäume. 2.1 Implementierung von Bäumen. 2.2 Implementierung eines binären Suchbaums. 2.3 Traversierung von Bäumen

2 Java: Bäume. 2.1 Implementierung von Bäumen. 2.2 Implementierung eines binären Suchbaums. 2.3 Traversierung von Bäumen 2 2 Java: Bäume 2.1 Implementierung von Bäumen 2.2 Implementierung eines binären Suchbaums 2.3 Traversierung von Bäumen 2.4 Implementierung von Heapsort 19 Teil II Java: Bäume Überblick Implementierung

Mehr

Eine zu Grunde liegende Typdefinition beschreibt eine Struktur, die alle erlaubten Instanzen dieses Typs gemeinsam haben.

Eine zu Grunde liegende Typdefinition beschreibt eine Struktur, die alle erlaubten Instanzen dieses Typs gemeinsam haben. Der binäre Baum Tree Die geläufigste Datenstuktur ist der binäre Baum Tree. Dieses Beispielskript zeigt im direkten Vergleich zu anderen Sprachen den Umgang mit formalen Typparametern in CHELSEA. Wir steigen

Mehr

Programmierung und Modellierung

Programmierung und Modellierung Programmierung und Modellierung Terme, Suchbäume und Pattern Matching Martin Wirsing in Zusammenarbeit mit Moritz Hammer SS 2009 2 Inhalt Kap. 7 Benutzerdefinierte Datentypen 7. Binärer Suchbaum 8. Anwendung:

Mehr

KONSTRUKTION VON ROT-SCHWARZ-BÄUMEN

KONSTRUKTION VON ROT-SCHWARZ-BÄUMEN KONSTRUKTION VON ROT-SCHWARZ-BÄUMEN RALF HINZE Institut für Informatik III Universität Bonn Email: ralf@informatik.uni-bonn.de Homepage: http://www.informatik.uni-bonn.de/~ralf Februar, 2001 Binäre Suchbäume

Mehr

Klausur in Programmieren

Klausur in Programmieren Studiengang Sensorik/Sensorsystemtechnik Note / normierte Punkte Klausur in Programmieren Winter 2009/2010, 18. Februar 2010 Dauer: 1,5h Hilfsmittel: Keine (Wörterbücher sind auf Nachfrage erlaubt) Name:

Mehr

10. Kapitel (Teil1) BÄUME GRUNDLAGEN. Algorithmen & Datenstrukturen Prof. Dr. Wolfgang Schramm

10. Kapitel (Teil1) BÄUME GRUNDLAGEN. Algorithmen & Datenstrukturen Prof. Dr. Wolfgang Schramm 10. Kapitel (Teil1) BÄUME GRUNDLAGEN Algrithmen & Datenstrukturen Prf. Dr. Wlfgang Schramm Übersicht 1 1. Einführung 2. Algrithmen 3. EigenschaCen vn Prgrammiersprachen 4. Algrithmenparadigmen 5. Suchen

Mehr

PIWIN 1 Übung Blatt 5

PIWIN 1 Übung Blatt 5 Fakultät für Informatik Wintersemester 2008 André Gronemeier, LS 2, OH 14 Raum 307, andre.gronemeier@cs.uni-dortmund.de PIWIN 1 Übung Blatt 5 Ausgabedatum: 19.12.2008 Übungen: 12.1.2009-22.1.2009 Abgabe:

Mehr

Binäre Suchbäume. Ein Leitprogramm von Timur Erdag und Björn Steffen

Binäre Suchbäume. Ein Leitprogramm von Timur Erdag und Björn Steffen Binäre Suchbäume Ein Leitprogramm von Timur Erdag und Björn Steffen Inhalt: Bäume gehören zu den bedeutendsten Datenstrukturen in der Informatik. Dieses Leitprogramm gibt eine Einführung in dieses Thema

Mehr

Programmiertechnik II

Programmiertechnik II Analyse von Algorithmen Algorithmenentwurf Algorithmen sind oft Teil einer größeren Anwendung operieren auf Daten der Anwendung, sollen aber unabhängig von konkreten Typen sein Darstellung der Algorithmen

Mehr

Abschnitt: Algorithmendesign und Laufzeitanalyse

Abschnitt: Algorithmendesign und Laufzeitanalyse Abschnitt: Algorithmendesign und Laufzeitanalyse Definition Divide-and-Conquer Paradigma Divide-and-Conquer Algorithmen verwenden die Strategien 1 Divide: Teile das Problem rekursiv in Subproblem gleicher

Mehr

Übungspaket 19 Programmieren eigener Funktionen

Übungspaket 19 Programmieren eigener Funktionen Übungspaket 19 Programmieren eigener Funktionen Übungsziele: Skript: 1. Implementierung und Kodierung eigener Funktionen 2. Rekapitulation des Stack-Frames 3. Parameterübergabe mittels Stack und Stack-Frame

Mehr

6 Baumstrukturen. Formale Grundlagen der Informatik I Herbstsemester 2012. Robert Marti

6 Baumstrukturen. Formale Grundlagen der Informatik I Herbstsemester 2012. Robert Marti 6 Baumstrukturen Formale Grundlagen der Informatik I Herbstsemester 2012 Robert Marti Vorlesung teilweise basierend auf Unterlagen von Prof. emer. Helmut Schauer Beispiel: Hierarchisches File System 2

Mehr

Tutoren Simon Andermatt Lukas Beck. Alexis Peter Thomas Ritter

Tutoren Simon Andermatt Lukas Beck. Alexis Peter Thomas Ritter UNIVERSITÄT BASEL Dozent Prof. Dr. Thomas Vetter Departement Informatik Assistenten Brian Amberg Andreas Forster Tutoren Simon Andermatt Lukas Beck Webseite http://informatik.unibas.ch/lehre/hs10/cs101/index.html

Mehr

Grundlagen der Programmierung 2. Bäume

Grundlagen der Programmierung 2. Bäume Grundlagen der Programmierung 2 Bäume Prof. Dr. Manfred Schmidt-Schauÿ Künstliche Intelligenz und Softwaretechnologie 24. Mai 2006 Graphen Graph: Menge von Knoten undzugehörige (gerichtete oder ungerichtete)

Mehr

- k Maximalwerte aus Menge mit n >> k Elementen (Rangfolgebestimmung von Suchmaschinen!) Die typische Operationen:

- k Maximalwerte aus Menge mit n >> k Elementen (Rangfolgebestimmung von Suchmaschinen!) Die typische Operationen: 6 Partiell geordnete binäre Bäume: Heap (Haufen) Motivation für manchen Anwendungen nur partielle Ordnung der Elemente statt vollständiger nötig, z.b. - Prioritätsschlange: nur das minimale (oder maximale)

Mehr

Vorkurs C++ Programmierung

Vorkurs C++ Programmierung Vorkurs C++ Programmierung Klassen Letzte Stunde Speicherverwaltung automatische Speicherverwaltung auf dem Stack dynamische Speicherverwaltung auf dem Heap new/new[] und delete/delete[] Speicherklassen:

Mehr

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = 0.51129 Euro ergeben.

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = 0.51129 Euro ergeben. Aufgabe 1.30 : Schreibe ein Programm DM_in_Euro.java zur Umrechnung eines DM-Betrags in Euro unter Verwendung einer Konstanten für den Umrechnungsfaktor. Das Programm soll den DM-Betrag als Parameter verarbeiten.

Mehr

Gegeben Zieladresse, finde Nachbarknoten, an den Paket zu senden ist ("Routing-Tabelle")

Gegeben Zieladresse, finde Nachbarknoten, an den Paket zu senden ist (Routing-Tabelle) 8 Digitalbäume, Tries,, Suffixbäume 8.0 Anwendungen Internet-outer egeben Zieladresse, finde Nachbarknoten, an den Paket zu senden ist ("outing-tabelle") 3 network addr Host id 00 0000 000 0 00 0 0000

Mehr

C/C++ Programmierung

C/C++ Programmierung 1 C/C++ Programmierung Verbunde, Reihungen, Zeiger Sebastian Hack Christoph Mallon (hack mallon)@cs.uni-sb.de Fachbereich Informatik Universität des Saarlandes Wintersemester 2009/2010 2 Typen 6.2.5 Primitive

Mehr

Java programmieren: Konsolen-Programme

Java programmieren: Konsolen-Programme Java programmieren: Es war einmal vor langer Zeit in einer weit entfernten Galaxis ok, das ist etwas übertrieben. In den Anfängen der Personal Computer in den 1980er sahen Computer noch etwa so aus: Diese

Mehr

ABITURPRÜFUNG 2009 LEISTUNGSFACH INFORMATIK

ABITURPRÜFUNG 2009 LEISTUNGSFACH INFORMATIK ABITURPRÜFUNG 2009 LEISTUNGSFACH INFORMATIK (HAUPTTERMIN) Bearbeitungszeit: 270 Minuten Hilfsmittel: Wörterbuch zur deutschen Rechtschreibung Taschenrechner (nicht programmierbar, nicht grafikfähig) (Schüler,

Mehr

Kapitel 9 Suchalgorithmen

Kapitel 9 Suchalgorithmen Kapitel 9 Suchalgorithmen Technische Universität München Suchverfahren: Verfahren, das in einem Suchraum nach Mustern oder Objekten mit bestimmten Eigenschaften sucht. Vielfältige Anwendungsbereiche für

Mehr

Algorithmik II. a) Fügen Sie in einen anfangs leeren binären Baum die Schlüsselfolge 20, 28, 35, 31, 9, 4, 13, 17, 37, 25 ein.

Algorithmik II. a) Fügen Sie in einen anfangs leeren binären Baum die Schlüsselfolge 20, 28, 35, 31, 9, 4, 13, 17, 37, 25 ein. Aufgabe 10 Binäre Bäume a) Fügen Sie in einen anfangs leeren binären Baum die Schlüsselfolge, 28, 35, 31, 9, 4,, 17, 37, 25 ein. 1. Einfügen von : 3. Einfugen von 35: 2. Einfügen von 28: 28 28 10. Einfügen

Mehr

Sortierte Folgen 250

Sortierte Folgen 250 Sortierte Folgen 250 Sortierte Folgen: he 1,...,e n i mit e 1 apple applee n kennzeichnende Funktion: M.locate(k):= addressof min{e 2 M : e k} Navigations Datenstruktur 2 3 5 7 11 13 17 19 00 Annahme:

Mehr

Kostenmaße. F3 03/04 p.188/395

Kostenmaße. F3 03/04 p.188/395 Kostenmaße Bei der TM nur ein Kostenmaß: Ein Schritt (Konfigurationsübergang) kostet eine Zeiteinheit; eine Bandzelle kostet eine Platzeinheit. Bei der RAM zwei Kostenmaße: uniformes Kostenmaß: (wie oben);

Mehr

13 Java 4 - Entwurfsmuster am Beispiel des Rucksackproblems

13 Java 4 - Entwurfsmuster am Beispiel des Rucksackproblems 13 Java 4 - Entwurfsmuster am Beispiel des Rucksackproblems 13.1 Modellierung des Rucksackproblems 13.2 Lösung mit Greedy-Algorithmus 13.3 Lösung mit Backtracking 13.4 Lösung mit Dynamischer Programmierung

Mehr

Jahresabschluss- rechnung und Rückstände

Jahresabschluss- rechnung und Rückstände ACS Data Systems AG Jahresabschluss- rechnung und Rückstände (Version 10.08.2009) Buchhaltung für Schulen ACS Data Systems AG Bozen / Brixen / Trient Tel +39 0472 27 27 27 obu@acs.it 2 Inhaltsverzeichnis

Mehr

Schnittstellen implementieren am Beispiel Suchbaum

Schnittstellen implementieren am Beispiel Suchbaum Motivation Informatik mit Java und BlueJ Schnittstellen implementieren am Beispiel Suchbaum von Bernhard Rosing Schreiben Sie eine Klasse Person, deren Instanzen in ein TreeSet (Suchbaum) eingefügt werden

Mehr

Programmierkurs: Delphi: Einstieg

Programmierkurs: Delphi: Einstieg Seite 1 von 6 Programmierkurs: Delphi: Einstieg Aus Wikibooks Inhaltsverzeichnis 1 Einstieg Einstieg Was ist Delphi Borland Delphi ist eine RAD-Programmierumgebung von Borland. Sie basiert auf der Programmiersprache

Mehr

Kapitel 4: Dynamische Datenstrukturen. Algorithmen und Datenstrukturen WS 2012/13. Prof. Dr. Sándor Fekete

Kapitel 4: Dynamische Datenstrukturen. Algorithmen und Datenstrukturen WS 2012/13. Prof. Dr. Sándor Fekete Kapitel 4: Dynamische Datenstrukturen Algorithmen und Datenstrukturen WS 2012/13 Prof. Dr. Sándor Fekete 4.4 Binäre Suche Aufgabenstellung: Rate eine Zahl zwischen 100 und 114! Algorithmus 4.1 INPUT: OUTPUT:

Mehr

Beispielblatt 2 186.813 VU Algorithmen und Datenstrukturen 1 VU 6.0

Beispielblatt 2 186.813 VU Algorithmen und Datenstrukturen 1 VU 6.0 Beispielblatt 2 186.813 VU Algorithmen und Datenstrukturen 1 VU 6.0 25. September 2013 Aufgabe 1 Gegeben sei ein binärer Suchbaum mit Werten im Bereich von 1 bis 1001. In diesem Baum wird nach der Zahl

Mehr

Grundlagen Programmierung

Grundlagen Programmierung 1. Aufgabe (Spielen mit Objekten) Gegeben sei der auch von der Veranstaltungsseite erhältliche Programmcode auf der rechten Seite, der im Detail zuerst nicht verstanden werden muss. a) Erzeugen Sie sich

Mehr

Übersicht. Informatik 2 Teil 3 Anwendungsbeispiel für objektorientierte Programmierung

Übersicht. Informatik 2 Teil 3 Anwendungsbeispiel für objektorientierte Programmierung Übersicht 3.1 Modell Konto 3.2 Modell Konto - Erläuterungen 3.3 Benutzer Ein- und Ausgabe mit Dialogfenster I 3.4 Benutzer Ein- und Ausgabe mit Dialogfenster II 3.5 Klassen- und Objekteigenschaften des

Mehr

Von der UML nach C++

Von der UML nach C++ 22 Von der UML nach C++ Dieses Kapitel behandelt die folgenden Themen: Vererbung Interfaces Assoziationen Multiplizität Aggregation Komposition Die Unified Modeling Language (UML) ist eine weit verbreitete

Mehr

Projekt AGB-10 Fremdprojektanalyse

Projekt AGB-10 Fremdprojektanalyse Projekt AGB-10 Fremdprojektanalyse 17. Mai 2010 1 Inhaltsverzeichnis 1 Allgemeines 3 2 Produktübersicht 3 3 Grundsätzliche Struktur und Entwurfsprinzipien für das Gesamtsystem 3 3.1 Die Prefuse Library...............................

Mehr

Einführung in die Java- Programmierung

Einführung in die Java- Programmierung Einführung in die Java- Programmierung Dr. Volker Riediger Tassilo Horn riediger horn@uni-koblenz.de WiSe 2012/13 1 Wichtig... Mittags Pommes... Praktikum A 230 C 207 (Madeleine) F 112 F 113 (Kevin) E

Mehr

Institut für Informatik

Institut für Informatik Technische Universität München Institut für Informatik Lehrstuhl für Computer Graphik & Visualisierung WS 2010 Praktikum: Grundlagen der Programmierung Lösungsblatt 7 Prof. R. Westermann, A. Lehmann, R.

Mehr

Überblick. Lineares Suchen

Überblick. Lineares Suchen Komplexität Was ist das? Die Komplexität eines Algorithmus sei hierbei die Abschätzung des Aufwandes seiner Realisierung bzw. Berechnung auf einem Computer. Sie wird daher auch rechnerische Komplexität

Mehr

Algorithmen und Datenstrukturen Balancierte Suchbäume

Algorithmen und Datenstrukturen Balancierte Suchbäume Algorithmen und Datenstrukturen Balancierte Suchbäume Matthias Teschner Graphische Datenverarbeitung Institut für Informatik Universität Freiburg SS 12 Überblick Einführung Einfügen und Löschen Einfügen

Mehr

t r Lineare Codierung von Binärbbäumen (Wörter über dem Alphabet {, }) Beispiel code( ) = code(, t l, t r ) = code(t l ) code(t r )

t r Lineare Codierung von Binärbbäumen (Wörter über dem Alphabet {, }) Beispiel code( ) = code(, t l, t r ) = code(t l ) code(t r ) Definition B : Menge der binären Bäume, rekursiv definiert durch die Regeln: ist ein binärer Baum sind t l, t r binäre Bäume, so ist auch t =, t l, t r ein binärer Baum nur das, was durch die beiden vorigen

Mehr

Codierung. Auszug aus dem Skript von Maciej Liśkiewicz und Henning Fernau

Codierung. Auszug aus dem Skript von Maciej Liśkiewicz und Henning Fernau Codierung Auszug aus dem Skript von Maciej Liśkiewicz und Henning Fernau Ein bisschen Informationstheorie Betrachten wir das folgende Problem: Wie lautet eine sinnvolle Definition für das quantitative

Mehr

Suchen und Sortieren Sortieren. Heaps

Suchen und Sortieren Sortieren. Heaps Suchen und Heaps (Folie 245, Seite 63 im Skript) 3 7 21 10 17 31 49 28 14 35 24 42 38 Definition Ein Heap ist ein Binärbaum, der die Heapeigenschaft hat (Kinder sind größer als der Vater), bis auf die

Mehr

C/C++-Programmierung

C/C++-Programmierung 1 C/C++-Programmierung Aufzählungen, Zeichenketten Sebastian Hack Christoph Mallon (hack mallon)@cs.uni-sb.de Fachbereich Informatik Universität des Saarlandes Wintersemester 2009/2010 2 Aufzählungen enumerations,

Mehr

Programmierung einer Windows Store App mit C# und XAML

Programmierung einer Windows Store App mit C# und XAML Neuer Abschnitt 1 Seite 1 Programmierung einer Windows Store App mit C# und XAML Einleitung In diesem Fachbericht der im Rahmen meines 8 Wochen langem Praktikums entstand geht es um die Programmierung

Mehr

Einführung in (Binäre) Bäume

Einführung in (Binäre) Bäume edeutung und Ziele inführung in (inäre) äume Marc Rennhard http://www.tik.ee.ethz.ch/~rennhard rennhard@tik.ee.ethz.ch äume gehören ganz allgemein zu den wichtigsten in der Informatik auftretenden atenstrukturen,

Mehr

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen Algorithmen und Datenstrukturen Dipl. Inform. Andreas Wilkens 1 Organisatorisches Freitag, 05. Mai 2006: keine Vorlesung! aber Praktikum von 08.00 11.30 Uhr (Gruppen E, F, G, H; Vortestat für Prototyp)

Mehr

Softwaretechnik (WS 11/12)

Softwaretechnik (WS 11/12) Universität Augsburg, LSt. Softwaretechnik, K. Stenzel, H. Seebach, G. Anders Softwaretechnik (WS 11/12) Lösungsvorschlag 5 Aufgabe 1 (System Behavior: System Sequence Diagrams) (10/5 Punkte) a) Was sind

Mehr

Suchen und Sortieren (Die klassischen Algorithmen)

Suchen und Sortieren (Die klassischen Algorithmen) Suchen und Sortieren (Die klassischen Algorithmen) Lineare Suche und Binäre Suche (Vorbedingung und Komplexität) Sortieralgorithmen (allgemein) Direkte Sortierverfahren (einfach aber langsam) Schnelle

Mehr

Autor: Michael Spahn Version: 1.0 1/10 Vertraulichkeit: öffentlich Status: Final Metaways Infosystems GmbH

Autor: Michael Spahn Version: 1.0 1/10 Vertraulichkeit: öffentlich Status: Final Metaways Infosystems GmbH Java Einleitung - Handout Kurzbeschreibung: Eine kleine Einführung in die Programmierung mit Java. Dokument: Autor: Michael Spahn Version 1.0 Status: Final Datum: 23.10.2012 Vertraulichkeit: öffentlich

Mehr

Technische Beschreibung: EPOD Server

Technische Beschreibung: EPOD Server EPOD Encrypted Private Online Disc Technische Beschreibung: EPOD Server Fördergeber Förderprogramm Fördernehmer Projektleitung Projekt Metadaten Internet Foundation Austria netidee JKU Linz Institut für

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Universität der Bundeswehr Fakultät für Informatik Institut 2 Priv.-Doz. Dr. Lothar Schmitz FT 2006 Zusatzaufgaben Lösungsvorschlag Objektorientierte Programmierung Lösung 22 (Java und UML-Klassendiagramm)

Mehr

15 Optimales Kodieren

15 Optimales Kodieren 15 Optimales Kodieren Es soll ein optimaler Kodierer C(T ) entworfen werden, welcher eine Information (z.b. Text T ) mit möglichst geringer Bitanzahl eindeutig überträgt. Die Anforderungen an den optimalen

Mehr

7 Die Reorganisation von DB2

7 Die Reorganisation von DB2 Ab und an sollte eine Tabelle reorganisiert werden. Besonders, nachdem größere Datenmengen eingefügt oder gelöscht wurden, muß über eine Reorganisation nachgedacht werden. Eine optimale Performance ist

Mehr