1 Aufgaben 1. Hash-Table für void-Pointer 2. Binomial-Heaps für void-Pointer 3. Strassen-Algorithmus, Parser für Matrix-Dateien 4. Determinante einer n × n-Matrix, Parser für Matrix-Dateien 5. Aho-Corasick-Algorithmus 6. Dijkstra, Graph aus Datei lesen 7. Floyd-Warshall, Graph aus Datei lesen 8. Topologische Sortierung, Graph aus Datei lesen 9. Taschenrechner 10. Hirschberg-Algorithmus 11. SpamAssassin Lite; Lern- und Klassifizierungsprogramm, Bayes, sqlite3 12. Breve/Steve Abgabe: August 2008. per E-Mail an: gsauthof(at)techfak.uni-bielefeld.de rhomann(at)techfak.uni-bielefeld.de und 1.1 Voraussetzungen • übersetzbar und lauffähig auf den Plattformen in der TechFak (Solaris/SPARC, Solaris/x86 und Linux/x86) • Verwendung von make • Testprogramm und -daten • C89 oder C99, keine Compiler-Erweiterungen (mit -ansi oder -std=c99 übersetzen) • Einzelarbeit, keine Plagiate 1 1.2 Details 1.2.1 Hash-Table (Kathrin Buchhorn) Die API soll es zulassen, eine beliebige Hash-Funktionen bei Verwendung der Hash-Table angeben zu können. Per default soll eine multiplikative Hash-Funktion verwendet werden. Die konfigurierbare Resize-Strategie soll nicht nur von der Wahl einer neuen Tabellengröße, sondern auch von dem verwendeten Speicher-Allokator abstrahieren. Ohne Angabe einer speziellen Funktion sollen eine vernünftige defaultresize-Strategie und malloc()/realloc() verwendet werden. Wird kein Load-Factor übergeben, soll ein vernünftiger Default verwendet werden. Literatur: [CLRS01] 1.2.2 Binomial-Heaps (Oliver Robrandt) Ein binärer Heap ist eine Datenstruktur zur Verwaltung einer Datenmenge, die es erlaubt, das kleinste (bzw. größte) Element der Menge in O(1) zu finden und in O(log n) zu entfernen (n = Anzahl der vom Heap verwalteten Elemente). Andere Operationen wie das Hinzufügen neuer Elemente laufen ebenfalls in O(log n), allerdings kostet die Vereinigung zweier binärer Heaps O(n) Zeit. Binomial-Heaps hingegen erlauben die Vereinigung in O(log n) Zeit, erkaufen diesen Vorteil aber durch eine Verlangsamung der Operation zur Suche nach dem kleinsten (größten) Element von O(1) auf O(log n). Die Aufgabe ist es, einen Binomial-Heap zu implementieren, der folgende Operationen unterstützt (min-heap): Make-Heap, Insert, Minimum, Extract-Min, Union, Decrease-Key, Delete. Es sollen void-Pointer gespeichert werden, die Vergleichsfunktion muss konfigurierbar sein. Literatur: [CLRS01] 1.2.3 Strassen-Algorithmus (Leon Kuchenbecker) Strassen’s Algorithmus ist ein effizienter rekursiver Algorithmus zu Multiplikation zweier n × n-Matrizen in O(nlog 7 ) Zeit. Die Eingabe für das Programm soll aus zwei Dateien bestehen, die jeweils eine n × n-Matrix speichern. Im Matrix-Dateiformat sind die Elemente der Matrix als Strings und durch Leerzeichen voneinander getrennt gespeichert. Das Ende jeder Matrix-Zeile wird durch ein Newline-Zeichen signalisiert. Literatur: [CLRS01], Wikipedia 2 1.2.4 Determinante berechnen (Stefan Marfilius) Es soll ein Programm zur Determinantenberechnung für n × n-Matrizen implementiert werden. Die Berechnung soll entweder mit Hilfe des Laplace’schen Entwicklungssatzes erfolgen, also rekursiv mit Entwicklung nach Spalten bzw. Zeilen, oder mit Hilfe des Gauß’schen Eliminationsverfahrens. Die Eingabe für das Programm ist eine Datei, die eine n × n-Matrix enthält. Dateiformat wie in 1.2.3. Literatur: jedes Mathebuch, Wikipedia, [CLRS01] 1.2.5 Aho-Corasick-Algorithmus (Stefanie Schirmer) Der Aho-Corasick-Algorithmus ist ein klassischer Algorithmus zur gleichzeitigen Suche nach mehreren Strings in einem Text. Der Algorithmus ist eine Generalisierung des bekannten Knuth-Morris-Pratt-Algorithmus. Gegeben eine Menge P von Strings und einen Text T sucht der Algorithmus gleichzeitig nach allen exakten Vorkommen der Strings aus P in T . Nach einer Vorverarbeitung von P wird der Text dabei nur einmal durchlaufen. Die Menge der zu suchenden Strings soll aus einer Textdatei mit jeweils einem String pro Zeile eingelesen und vorverarbeitet werden. Der Text soll aus einer weiteren Datei gelesen werden. Die Ausgabe erfolgt zeilenweise, so dass für jeden Treffer die Position des ersten Zeichens und der gefundene String selbst ausgegeben werden. Literatur: [Gus97, NR02] 1.2.6 Dijkstra (Stefan Wilsky) Gegeben einen gewichteten gerichteten Graphen G = (V, E) und zwei Knoten a, b ∈ V (Start- und Endpunkt) in G findet Dijkstra’s Algorithmus den Pfad mit minimalem Gewicht von a nach b in O(|V |2 + |E|) Zeit (oder O((|V | + |E|) log |V |) mit einem binären Heap). Der Einfachheit halber wird auch eine Lösung ohne Verwendung eines Heaps akzeptiert. Dateiformat: Pro Zeile eine Kante. Eine Kante ist ein 3-Tupel aus VertexName (von), Vertex-Name (nach) und Gewicht. Komponenten des Tupels sind durch Leerzeichen voneinander getrennt. Literatur: [CLRS01] 3 1.2.7 Floyd-Warshall (Mathias Wilhelm) Gegeben einen gewichteten gerichteten Graphen G = (V, E) findet der FloydWarshall-Algorithmus in O(|V |3 ) für alle Knotenpaare a, b ∈ V die kürzesten Pfade von a nach b. Im Gegensatz zu Dijkstra’s Algorithmus funktioniert dieser Algorithmus auch mit negativen Gewichten. Dateiformat wie in 1.2.6. Literatur: [CLRS01] 1.2.8 Topologische Sortierung (Evgeny Anisiforov) Eine topologische Sortierung eines zyklenfreien und gerichteten Graphen G = (V, E) ist eine Aufzählung der Knoten von G, so dass für jedes Knotenpaar u, v ∈ V mit einer Kante von u nach v der Knoten u in der Aufzählung vor Knoten v erscheint. Die Sortierung kann mit Hilfe einer Tiefensuche in O(|V | + |E|) Zeit erledigt werden. Da eine topologische Sortierung nicht möglich ist, wenn der Graph Zyklen enthält, muss das Programm überprüfen, ob ein Zyklus vorhanden ist. Gibt es einen Zyklus, dann soll das Programm diesen mit einer Fehlermeldung ausgeben. Dateiformat wie in 1.2.6, allerdings ohne die dritte Spalte mit den Gewichten. Literatur: [CLRS01] 1.2.9 Taschenrechner (Fabian Schrodt) Es soll ein Taschenrechner programmiert werden, der aus Gleitkommazahlen, den Grundrechenarten, Klammern und einigen speziellen Funktionen zusammengesetzen Rechenaufgaben verarbeiten kann. Die Operatoren +, -, *, / und ˆ sollen als Infix-Operatoren interpretiert werden. Der Rechner soll die Funktionen cos, log und wahlweise einige mehr verarbeiten können. Es gilt Punkt-vor-Strich-Rechnung. Beispieleingabe: 3 + 5.5 * 4ˆ2.5 * (1.3 + cos(log(1.0))) Ausgabe: 232.7 Die Eingabe sollte ein einziger String sein und nicht aus argv zusammengesucht werden. Literatur: [ALSU06, ASU86] 4 1.2.10 Hirschberg-Algorithmus (Samy Slaih) Der Hirschberg-Algorithmus berechnet das paarweise Sequenzalignment von zwei Sequenzen a und b in O(n2 ) Zeit und O(n) Speicher, mit n = max(|a| , |b|), nach der Divide-and-Conquer-Programmiermethode. Die beiden Sequenzen sollen jeweils aus einer Datei gelesen werden, wobei die erste Zeile bis zum ersten Newline-Zeichen eine Sequenz bedeutet. Die Kostenbzw. Optimierungsfunktion muss durch eine API austauschbar sein. Die Programmausgabe beinhaltet das optimale Alignment und den optimalen Alignment-Score. Co-Optimale Alignments müssen aus Gründen der Einfachheit nicht berücksichtigt werden. Literatur: [Gus97], Sequenzanalyse 2 Skript, Wikipedia 1.2.11 SpamAssassin Lite (Andreas Wixler) Zur Klassifikation von Mails in die Klassen „Ham“ und „Spam“ soll eine Datenbank von Worthäufigheiten in bekannten Ham- und Spam-Mails aufgebaut werden. Diese Häufigkeiten dienen als Grundlage für einen Bayes-Klassifikator, um neue Mails einer der beiden Klassen zuzuordnen. Den Worthäufigkeiten in der Datenbank muss ein Timestamp zugeordnet werden, der bei Updates gesetzt wird. Eine Programm-Funktion soll auf Benutzerwunsch die Datenbank verkleinern, indem ein sinnvoller Anteil der ältesten Einträge gelöscht wird. Die drei Hauptkomponenten Lernen, Klassifizieren und Datenbank verkleinern können in einem oder jeweils in einzelnen Programmen implementiert werden. Der zu lernende bzw. klassifizierende Text soll über eine Datei und über stdin eingelesen werden können. SQLite-Datenbanken sind „endian-sicher“ (diesbezüglich keine besonderen Tests auf den unterschiedlichen Plattformen nötig). Literatur: http://sqlite.org/, Wikipedia, c’t 2003/17 1.2.12 Breve/Steve (Max Christian Pohle) Parser für Steve (Programmiersprache) und Generierung von HTML-Dokumentation. Literatur: [ALSU06, ASU86] 5 Literatur [ALSU06] Alfred V. Aho, Monica S. Lam, Ravi Sethi, and Jeffrey D. Ullman. Compilers: Principles, Techniques, and Tools (2nd Edition). Addison Wesley, August 2006. [ASU86] Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman. Compilers: Principles, Techniques, and Tools. Addison-Wesley, Inc., 1986. [CLRS01] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. Introduction to Algorithms. The MIT Press, Cambridge, Massachusetts 02142, USA, second edition, 2001. [Gus97] Dan Gusfield. Algorithms on Strings, Trees, and Sequences: Computer Science and Computational Biology. Cambridge University Press, 1997. [NR02] Gonzalo Navarro and Mathieu Raffinot. Flexible Pattern Matching in Strings: Practical On-Line Search Algorithms for Texts and Biological Sequences. Cambridge University Press, New York, NY, USA, 2002. 6