¨Ubungsblatt 4

Werbung
Technische Universität Wien
Institut für Computergraphik und Algorithmen
Arbeitsbereich für Algorithmen und Datenstrukturen
184.263 Algorithmen und Datenstrukturen 1 VL 4.0
WS2006/07
Übungsblatt 4
für die Übung am Montag 15. bzw. Dienstag 16. Jänner 2007
Aufgabe 4.1
Beschreiben Sie in rund 10 Sätzen die grundlegende(n) Idee(n) hinter Hashtabellen, ihre Einsatzgebiete und ihre Vor- und gegebenenfalls auch Nachteile. Gehen Sie in Ihren Betrachtungen auch auf die Wahl einer guten Hashfunktionen und der richtigen Tabellengröße ein,
sowie auf (mögliche) Probleme bei zu hohem Füllgrad (Verhältnis besetzte ↔ freie Plätze in
der Tabelle).
Aufgabe 4.2
Gegeben sei eine Hashtabelle mit externer Verkettung der Überläufer mit fester Größe m =
10, sowie die Hashfunktion h(x) = (x + 3) mod 7.
• Ist diese Hashfunktion klug gewählt? Warum (nicht)?
• Fügen Sie in diese Hashtabelle nacheinander die Zahlen 3, 13, 4, 2, 6, 16, 9, 11 und 0
ein. Zeichnen Sie den Zustand der Hashtabelle Schritt für Schritt auf und denken Sie
anhand des Resultats nochmals über den ersten Punkt nach.
• Würden Sie die Tabellengröße oder die Hashfunktion ändern, um die Situation zu verbessern? Begründen Sie Ihre Wahl!
2
Aufgabe 4.3
Gegeben sei eine Hashtabelle der Größe m = 11. Der Zugriff soll mittels Linearem Sondieren mit der folgenden Hashfunktion erfolgen:
h0 (k) = k mod 11
Tragen Sie die folgenden Zahlen in dieser Reihenfolge in die Tabelle ein und zeichnen Sie jeweils den Zustand der Tabelle nach dem Eintragen jeder einzelnen Zahl:
h5, 21, 18, 3, 39, 9, 32, 14i.
Danach löschen Sie die Zahlen h21, 39, 3i. Schließlich fügen Sie noch die Zahlen h16, 7, 8i
ein. Zeichnen Sie wieder den Zustand der Tabelle nach jeder Operation.
Aufgabe 4.4
Gegeben ist eine Hashtabelle mit Quadratischem Sondieren, m = 10, h0 (k) = k mod m,
c1 = 3, c2 = 5.
• Fügen Sie die Zahlen der Folge h12, 13, 28, 10, 14, 32, 43i in der angegebenen Reihenfolge in diese Hashtabelle ein. Zeichnen Sie den Zustand der Tabelle nach dem Einfügen
jeder einzelnen Zahl.
• Zeigen Sie, dass die angegebene Hashfunktion nicht ideal ist. Tipp: Überlegen Sie, was
passieren würde, wenn Sie statt 43 als letzte Zahl 42 einfügen würden. Verbessern Sie
die Hashfunktion so, dass ein derartiges Problem nicht mehr auftreten kann.
Aufgabe 4.5
Gegeben ist eine Hashtabelle mit Double Hashing, welche die Verbesserung nach Brent
verwendet, m = 11, h1 (k) = k mod 11, h2 (k) = k mod 5 + 2 (beachten Sie, dass
die Modulo-Operation stärker bindet als die Addition). Fügen Sie die Zahlen der Folge
h12, 13, 28, 10, 14, 32, 43i in der angegebenen Reihenfolge in diese Hashtabelle ein. Zeichnen Sie den Zustand der Tabelle nach dem Einfügen jeder einzelnen Zahl.
Aufgabe 4.6
1. Gegeben ist eine Hashtabelle in Form eines Arrays feld mit der festgelegten Größe
m. Jedes Element feld [j], j = 0, . . . , m − 1, dieses Arrays besteht aus folgenden
Komponenten:
3
• feld [j].schl enthält den Schlüssel des Datensatzes;
• feld [j].daten enthält die eigentlichen Daten;
• feld [j].zustand enthält einen der folgenden Werte:
– besetzt: feld [j] enthält einen gültigen Datensatz;
– frei: feld [j] ist frei und war nie besetzt;
– wiederfrei: feld [j] war schon besetzt, ist aber wieder frei.
Schreiben Sie eine Prozedur in Pseudocode, welche diese Hashtabelle für die Verwendung mit Linearem Sondieren korrekt und vollständig initialisiert, aber auch keine
überflüssigen Initialisierungen vornimmt.
2. Nehmen Sie an, dass eine Hashfunktion b(k) existiert, die aus einem Schlüssel k einen
Hashindex in der oben deklarierten Tabelle berechnet. Schreiben Sie eine Prozedur in
Pseudocode, die den Datensatz mit dem Schlüssel gesucht aus der Tabelle entfernt,
falls er enthalten ist. Zur Behandlung von Kollisionen ist die konstante Schrittweite c1
zu verwenden.
3. Die oben genannten Schlüssel sind Zeichenketten in der Form, dass Sie auf die einzelnen Elemente eines Schlüssels schl als Zeichen schl .zeichen[i], i = 0, . . . , n − 1,
zugreifen können. Es existiert eine Funktion ord (z), welche den numerischen Wert
eines Zeichens z liefert. Schreiben Sie eine Hashfunktion b0 (k) in Pseudocode, welche
nach der Divisions-Rest-Methode vorgeht, um aus den Zeichen des Schlüssels k einen
Hashindex zu berechnen.
Aufgabe 4.7
Für einen Test aus Algorithmen und Datenstrukturen“ soll durch die Erstellung mehrerer
”
gleichwertiger Beispielgruppen das durchaus beliebte Schummeln möglichst verhindert werden.
Der Sitzplan eines Hörsaals wird als Graph G(V, E) realisiert. Dabei entspricht jeder Knoten
aus V einer Person mit einem Angabeblatt, und jede Kante aus E verbindet jeweils zwei
direkt benachbart (z.B. in einem Radius von maximal 2,5 Metern) sitzende Personen.
Nun muss jeder Person eine Beispielgruppe (A, B, C, . . . ) so zugeordnet werden, dass an
keiner Stelle des Hörsaals zwei Personen mit der gleichen Gruppe direkt benachbart sitzen.
Die Erstellung zusätzlicher Beispielgruppen verursacht natürlich auch entsprechend mehr
Arbeit. Daher ist das Ziel, mit möglichst wenigen Beispielgruppen trotzdem eine sichere
Testsituation zu schaffen.
4
Schreiben Sie einen Algorithmus in ausführlichem Pseudocode, der die oben beschriebene
Aufgabe für einen gegebenen Sitzplangraphen G mit Hilfe eines Verfahrens, das auf Tiefensuche (DFS) basiert, möglichst gut löst. Versuchen Sie dabei, jedem Knoten eine möglichst
(lexikographisch) kleine Beispielgruppe zuzuweisen.
Aufgabe 4.8
Gegeben sei ein zusammenhängender, ungerichteter Graph G(V, E), wobei jeder Kante e ∈
E ein positives Gewicht ce > 0 zugewiesen ist.
Schreiben Sie detaillierten Pseudocode für eine Prozedur FindPath(...) (und gegebenenfalls verwendete Unterprozeduren) für folgendes Problem:
Gesucht sind alle Pfade im Graphen G(V, E), die aus genau H Kanten bestehen und ein
Gesamtgewicht (Summe über alle Kantengewichte ce des Pfades) von mindestens L besitzen.
Geben Sie von einem solchen gefundenen Pfad den Start- und den Endknoten sowie das
Gesamtgewicht aus. Ein Pfad darf mehrmals ausgegeben werden.
Achten Sie besonders darauf, dass für eine Pfad gilt:
• Ein Pfad ist zusammenhängend und
• kreisfrei (d.h. in einem Pfad darf kein Knoten bzw. keine Kante mehrmals vorkommen).
Aufgabe 4.9
(a) Gegeben ist ein ungerichteter, zusammenhängender Graph G = (V, E) durch folgende
Adjazenzlisten-Darstellung:
v
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
N (v)
(4)
(3)
(4, 2)
(5, 3, 1)
(8, 6, 4)
(10, 8, 5)
(8)
(10, 7, 6, 5)
(10)
(9, 8, 6)
Zeichnen Sie den repräsentierten Graphen.
5
(b) Gegeben ist ferner folgender Algorithmus:
Algorithmus Was-bin-ich?
Input: Graph G = (V, E)
Output: Kantenmenge F und Feld X[1 . . . |V |]
1: F = {};
2: X[1 . . . |V |] = (−1, −1, . . . , −1);
3: A(4);
Prozedur A(v)
1: X[v] = X[v] + 1;
2: für alle Knoten w ∈ N (v) in der gegebenen Ordnung {
3:
falls X[w] < 0 dann {
4:
F = F ∪ (v, w);
5:
A(w);
6:
}
7:
X[w] = X[w] + 1;
8: }
Welche Kanten liefert der Algorithmus für den gegebenen Beispielgraphen in F zurück?
Markieren Sie diese Kanten in der Zeichnung zu ihrem Graphen. Welche Werte werden
im Feld X zurückgeliefert?
(c) Beschreiben Sie in einem Satz, was dieser Algorithmus allgemein für einen beliebigen
ungerichteten, zusammenhängenden Graphen macht und in F bzw. X zurückliefert.
Aufgabe 4.10
Breitensuche ist ein Verfahren zum Durchsuchen bzw. Durchlaufen von Knoten eines Graphen ähnlich der in der Vorlesung behandelten Tiefensuche. Auch hier geht man von einem
Startknoten u aus, allerdings unterscheiden sich nun Tiefen- und Breitensuche bei der Reihenfolge, in der weitere Knoten des Graphen abgearbeitet bzw. besucht werden. Wir gehen
im Folgenden bei diesem Beispiel von einem ungerichteten Graphen aus.
Ausgehend vom Startknoten u werden bei der Breitensuche zunächst alle adjazenten Knoten
besucht, d.h. alle Knoten v, für die eine Kante (u, v) im Graphen existiert; zusätzlich werden
alle Knoten v in einer Warteschlange gespeichert. Die Breitensuche bearbeitet also zuerst
immer alle direkt benachbarten Knoten und folgt nicht – wie die Tiefensuche – gleich einem
Pfad in die Tiefe.
Nachdem nun alle adjazenten Knoten von u betrachtet wurden, wird der erste Knoten der
Warteschlange entnommen und für diesen das Verfahren rekursiv wiederholt. Dies wird nun
so lange fortgesetzt, bis entweder die Warteschlange leer ist, d.h. alle Knoten besucht wurden, bzw. bis – wenn man nach einem bestimmten Knoten sucht – dieser gefunden wurde.
6
Wie auch bei der Tiefensuche werden durch Markierungen bereits bearbeiteter Knoten Mehrfachbesuche von Knoten verhindert.
Gegeben sei nun die Datenstruktur Queue (Warteschlange), welche eine beliebige Menge
an Objekten aufnehmen und diese in der Reihenfolge ihres Einfügens wieder zurück liefern
kann. Folgende Operationen sind auf der Queue definiert:
• enqueue(X): Fügt ein Objekt X in die Queue ein.
• dequeue(): Entfernt das älteste Objekt aus der Queue und liefert es zurück.
Benutzen Sie die Queue, um eine nicht rekursive Version von Breitensuche zu entwerfen.
Beschreiben Sie erst in wenigen Worten den Ablauf Ihres Algorithmus und geben Sie ihn
dann in Pseudocode an. Die Queue können Sie dabei als “Black Box” betrachten, d.h. Sie
können sie benutzen, ohne die genaue Funktionsweise explizit als Pseudocode ausarbeiten
zu müssen.
Herunterladen