Upload
lethien
View
224
Download
0
Embed Size (px)
Citation preview
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
8 Weitere Algorithmen
Algorithmenmuster (Design Patterns):
� Scanline,
� Rekursion, Divide–and–Conquer,
� Graphendurchlauf: DFS, BFS,
� Backtracking in Verbindung mit DFS,
� Greedy,
� Dynamische Programmierung.
Prof. Dr. Dietmar Seipel 416
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
8.1 Das Algorithmenmuster Greedy
greedy: engl. für gierig
Das Prinzip “gieriger” Algorithmen ist es, in jedem Teilschritt so viel wie
möglich zu erreichen.
� Bei einigen Problemen wie der Berechnung kürzester Wege oder der
Suche nach einem aufspannenden Baum in einem Graphen kann man
mit einer geeigneten Greedy–Methode die Optimallösung finden.
� Bei anderen Problemen wie etwa dem Rucksackproblem oder dem
Problem des Handlungsreisenden erreicht man damit aber meist nicht
die Optimallösung.
Prof. Dr. Dietmar Seipel 417
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Berechnung kürzester Wege auf Distanzgraphen –Algorithmus von Dijkstra
Anwendung von Vorangswarteschlangen
Gegeben sei ein gerichteter Graph � � ��� ��� � , dessen Kanten � mit
nicht–negativen Längen � � �� markiert sind (Distanzgraph).
Desweiteren wird ein Knoten � � fixiert.
Gesucht sind die Längen � ��� � � ��� � � von kürzesten Wegen� � � ��� � von � zu
allen anderen Knoten� � .
Prof. Dr. Dietmar Seipel 418
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Beispiel:
� � � ��� ��� � � �� ��� � � �� ��� � � �� � � � � �� � � � �� � � � � �� � � � �� � � � � � �� � � � � � � � �
� � � � ��� ��� �� � � � �
Prof. Dr. Dietmar Seipel 419
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Dann gilt:� � � � � � � �
� �� � � � � ��� �� � � � � � � � ��� ��� � � � � � � �
� ��� � � � ��� ��� � � � � �� �� � � � � �
� � �
Prof. Dr. Dietmar Seipel 420
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Greedy–Algorithmus, Dijkstra
Setze� � � � � � ,
� � �� � � �� , für alle� � � � �� � ,
� � � � .
Dann wird � nach dem Prinzip „Knoten mit kürzester Distanz von � zuerst“schrittweise vergrößert, bis man � � � erhält:
1. Wähle Knoten� � � � mit minimaler Distanz� �� � .
2. Nimm� zu � hinzu( � � ��� � � � � � � � � �� � ist bereits korrekt!)
3. Füre jede Kante �� ��� � � von� zu� � � � , ersetze� �� � durch:
� � � �� � �� �� � � � �� ��� � �Prof. Dr. Dietmar Seipel 421
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Für alle Kanten aus � kennt man bereits die Länge � �� � � ��� � � eines
kürzesten Weges von � nach� .
Prof. Dr. Dietmar Seipel 422
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Wir implementieren� � � als Vorrangswarteschlange (Priority Queue). Die
Prioritäten sind die Distanzen� �� � .
Dann werden die 3 Schritte aus dem Algorithmus von Dijkstra
folgendermaßen realisiert:
1. Löschen des Minimums.
2. Einfügen.
3. Verringerung der Priorität eines Schlüssels.
Prof. Dr. Dietmar Seipel 423
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
8.2 Algorithmen zum Graphendurchlauf� Tiefensuche (Depth First Search, DFS)
� Breitensuche (Breadth First Search, BFS)
Anwendung zur Suche in Labyrinthen
Prof. Dr. Dietmar Seipel 424
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Das Labyrinth wird als Graph � � �� � � � repräsentiert:
� � � � � ��� � �
� � � � � ��� � � �� ��� � � �� ��� � � �� � � � � �� � � � � � � � � � � � � ��� � � �� � � � �
Wir lassen der Einfachheit halber die inversen Kanten des Labyrinths weg.
Prof. Dr. Dietmar Seipel 425
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Rahmenalgorithmus zum Graphendurchlauf
� Graph � � ��� ��� � ,
� Startknoten � � ,
� Zielknotenmenge � � � ,
� Datenstruktur � �� �� � für Knotenmenge
� Teilmengen � � � � � � und �� �� � � � .
Es werden kürzeste Wege von � zu allen Knoten aus � berechnet.
Prof. Dr. Dietmar Seipel 426
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
füge � in � �� �� � ein; �� �� �� � � � � ; � � �� � � ;
solange � � � �� � noch Elemente enthält
wähle das erste Element � aus � �� �� �
falls es keine Kante � � ��� ��� � � � �� � mit Knoten � gibt
dann lösche � aus � �� �� �
sonst { benutze eine Kante � � ��� ��� � � � �� � ,d.h. � � �� � � � �� � � � � � �� � � ;falls � �� �� �� �� �dann { �� �� �� � �� �� �� � � � � � ;
füge � in � �� �� � ein;
Vorgänger �� � � ;falls � � � � �� �� �
dann breche den Algorithmus ab } }
Prof. Dr. Dietmar Seipel 427
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Suche nach einem einzigen Zielknoten in JAVA
class GraphNode {
GraphNode[] neighbors;
boolean isVisited;
int key;
public GraphNode(int key) {
this.key = key;
}
public void setNeighbors(GraphNode... neighbors) {
this.neighbors = neighbors;
}
Prof. Dr. Dietmar Seipel 428
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
public List findPath(GraphNode destination) {
if (isVisited)
return null;
isVisited = true;
List path = null;
if (destination.key == this.key) {
path = new List();
path.add(key);
} else {
for (int i = 0; i < neighbors.length; i++) {
path = neighbors[i].findPath(destination);
if (path != null) {
path.insert(key, null);
break; } } }
return path;
}
Prof. Dr. Dietmar Seipel 429
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
public static void main(String[] args) {
GraphNode[] nodes = new GraphNode[5];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new GraphNode(i);
}
nodes[0].setNeighbors(nodes[1]);
nodes[1].setNeighbors(nodes[2], nodes[0]);
nodes[2].setNeighbors(nodes[3], nodes[4]);
nodes[3].setNeighbors(nodes[4]);
nodes[4].setNeighbors(nodes[1]);
System.out.println(nodes[4].findPath(nodes[0]));
}
}
Prof. Dr. Dietmar Seipel 430
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Tiefensuche:
Falls Border als Stapel realisiert wird, so ist das erste Element von Border
immer das oberste und wir fügen ein indem wir auf den Stapel legen.
Dann liefert der Rahmenalgorithmus eine Tiefensuche.
Beispiel:
Prof. Dr. Dietmar Seipel 431
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Sei � � � und � � � � � .
Die Knoten werden in der Reihenfolge ihrer Nummern besucht.� Für� � � wird zuerst die Kante �� � � � benutzt.
� Für� � � gibt es keine Kanten �� ��� � � . Deshalb fahren wir mit dernächsten unbenutzten Kante �� � � � für� � � fort (Backtracking) .
� Dann wird� � � analog zu� � � behandelt, und wir gelangenschließlich über den Knotem 8 zum Ziel 9.
� Die berechnete Vorgängerfunktion ist jetzt wie folgt:
� 1 2 3 4 5 6 7 8 9
Vorgänger �� � � 1 2 3 4 4 6 6 8
� Der berechnete Weg vom Start zum Ziel ist also:
� � �� ��� �� � � �� ��� �
Prof. Dr. Dietmar Seipel 432
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Breitensuche:
Falls Border als Priority Queue (First In / First Out) realisiert wird, so
liefert der Rahmenalgorithmus eine Breitensuche
Sei weiter � � � und � � � � � .
Auch hier werden die Knoten wieder in der Reihenfolge ihrer Nummern
besucht und der berechnete Weg ist der derselbe. Aber jetzt werden für
� � � zuerst die beiden Kanten �� � � � und �� � � � benutzt.
Die Priority Queue verändert sich wie folgt:
�
Benutzen von � � ��� �� � � �Benutzen von � � ��� �� � � � �
Erst jetzt wird 4 gelöscht, und wir besuchen� � � .
Prof. Dr. Dietmar Seipel 433
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Bei der Tiefensuche verändert sich Border dagegen wie folgt:�
Benutzen von � � � � �� � � �
Löschen von �� � �
Benutzen von � � � � �� � � �
Benutzen von � � ��� �� � � � �
�
Löschen von �� � � � � � � � � � � �
In der Tat ist der Stack am Ende gleich� � � � � � � �
d.h. gleich dem inversen gefundenen Weg vom Start zum Ziel.
Prof. Dr. Dietmar Seipel 434
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Falls die Sackgasse bei� � � länger wäre, so wäre die Breitensuche teurer
als die Tiefensuche.
Prof. Dr. Dietmar Seipel 435
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Die Tiefensuche benutzt die Kanten in folgender Reihenfolge:
� � �� � � �� �� � � �� �� � � �� � � � � � � � � � � � � � � � � � � � � � � � � � �
�� � � � � � � � � � � � � �� � � �� ��� �
Die Breitensuche benutzt dagegen nur folgende Kanten:
� � �� � � �� �� � � �� �� � � �� � � � � �� � � � �
� � � � � � � � � � � � � � �� � � � � � � � � � �� � � �Die Kanten zwischen 11 und 13 werden gar nicht benutzt.
Prof. Dr. Dietmar Seipel 436
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
In vielen praktischen Fällen werden sogar unterschiedliche Wege berechnet:
� � � � � �� � � �� �� � � �� �� � � � � �� � � �
� � � �
� � � � �
Tiefensuche: � � �� ��� �� � ,Breitensuche: � � �� �
Die Breitensuche brechnet immer einen kürzesten Weg, wenn man dieKantenlängen alle auf 1 setzt.In diesem Fall entspricht der Graphendurchlauf dem Algorithmus von
Dijkstra.
Prof. Dr. Dietmar Seipel 437
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Tiefensuche in Graphen mit Zyklen
Benutzung der Kanten:
(1,2), (2,3), (3,4), (4,5), (3,5), (3,6), (6,2), (6,5).
Die 5 unterstrichenen Kanten bilden einen Baum.
Prof. Dr. Dietmar Seipel 438
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Die weiteren Kanten heißen:
� Vorwärtskanten: �� � � �
� Rückwärtskanten: � � �� �
� Seitwärtskanten: � � � � �
Prof. Dr. Dietmar Seipel 439
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
8.3 Tiefensuche und Backtracking in PROLOG
PROLOG ermöglicht
� deklarative Programmierung
� kompakte Programme
� rapid Prototyping
Die Auswertungsstrategie der SLDNF–Resolution benutzt
� Tiefensuche
� Backtracking
� Unifikation
Prof. Dr. Dietmar Seipel 440
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Datenstrukturen in PROLOG
PROLOG–Atom: z.B. book, george, ‘George‘, x12op
Konstante: PROLOG–Atom � Numberz.B. book, 0, 123, 4
Variable: beginnend mit Großbuchstaben oder mit “_”z.B. Book, Up, Var, _, _X
Funktor (Funktions– bzw. Prädikatensymbol):Operator � PROLOG–Atomz.B. +, –, � , ancestor
Struktur: Konstante � Variable � Funktor(Struktur, , Struktur)z.B. +(1,7), ancestor(bill,joe)Listen sind spezielle Strukturen zum Funktor ’.’:[a,b,c,d] = ’.’(a, [b,c,d])+(1,7) ist äquivalent zu 1+7 (Infix–Notation).
Prof. Dr. Dietmar Seipel 441
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
PROLOG–Klauseln
(Prädikatensymbole: ancestor, parent, likes, woman, nice, loves)
Regeln: Kopf :– Rumpf, mit Konjunktion “,”, Disjunktion “;”� � �� �� �� �� �� � :– � � �� �� �� �� ��� � � �� � � � �� �� �
Bedeutung:
�� ��� � � � � ��� � ��� � �� ��� ��� � � � � � �� � � � ��� �� � ��� � �� � � � �
��� � � �� � �� � � ��� � :–� �� � � �� � � � �� � � �� � � � � � � �
��� � � �� �� ! � � � :– � � �� �� �" � �# � � �� � � � � � �
Fakten:
� �� � � �� �� ! �
��� � � �� �� ! � � � � � � �
� � # � � �� � �� � � � � � � � �
Goal:
$ � ��� � � � � � � � � � ��� �
Prof. Dr. Dietmar Seipel 442
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Ein PROLOG–Interpreter versucht ein Goal durch Inferenz zu beweisen.
Dies erfolgt Top–Down vom Goal ausgehend durch DFS–Durchlauf des
SLD–Baumes.
Beispiel:
?- likes(george,Y).
Y = maryYes?- likes(X, Y).
X = george, Y = mary ;X = mary, Y = georgeYes?-
Prof. Dr. Dietmar Seipel 443
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
SLD–Baum
� ���� � ��� �� �
� � � � �� �� � ��� � �� ��� � �� � � � � ��� �� �� �� �� � �� ���� � � �
�
� � �� � � � � � � �� � � �� � � �
success
� � ��� � � � � � � � � � �� � �
�
� � �� � � �� � � �� �� � � � � �
success
� � � � �� � �� � �� ���� � �� � �� � � � � �� � �� � ��� �� � � � � �� �� �� � �� � � � � ���� � � �
failurefailure
� � � �
�
� � � � �
!
""""#
$ $ $ $%
&''''''(
) ) ) ) ) )*&
&
Prof. Dr. Dietmar Seipel 444
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Anfragen in PROLOG� Die Auswertung von PROLOG–Regeln erfolgt Top–Down mittels der
Methode der SLDNF–Resolution: d.h., aus einer Anfrage an das
Kopfatom einer Regel werden Unteranfragen an die Rumpfatome der
Regel erzeugt.
� Dies entspricht dem Vorgehen bei der Abarbeitung von prozeduralen
Programmiersprachen.
� Falls ein Rumpfatom mehrere Antworten liefert, so wird zuerst mit
einer solchen Antwort weitergerechnet (Tiefensuche); falls die
Berechnung später fehlschlägt, so kann mit der nächsten Antwort
fortgefahren werden (Backtracking).
� In der Praxis sind viele PROLOG–Prädikate aber funktional; d.h., aus
einer Eingabe wird genau eine Ausgabe erzeugt.
Prof. Dr. Dietmar Seipel 445
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Kontrollprimitive, welche über die PL1 hinausgehen:
� “assert” und “retract” verändern die interne Datenbank von PROLOG;
“clause” sucht in dieser.
� “call” ruft Goals auf, die vorher zusammengebaut werden können.
� Der Cut “!” friert die bisherige Variablenbelegung in der aktuellen
Regel ein.
� “fail” ist ein Goal, das immer fehl schlägt.
�
Prof. Dr. Dietmar Seipel 446
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Literatur� W.F. Clocksin, C.S. Mellish:
Programming in PROLOG, Springer, 1987.
� I. Bratko: PROLOG – Programming for Artificial Intelligence,
Addison–Wesley, Second Edition, 1990.
� S. Ceri, G. Gottlob, L. Tanca:
Logic Programming and Databases, Springer, 1990.
� J.W. Lloyd:
Foundations of Logic Programming, Springer, Second Edition, 1987.
Prof. Dr. Dietmar Seipel 447
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Listen sind spezielle PROLOG–Strukturen mit dem binären Funktor ‘.’.
Liste: [a,b,c,d] = ’.’(a, ’.’(b, ’.’(c, ’.’(d, [ ]))))
Listenkonstruktion:Falls X und Xs bereits gebunden (mit Werten belegt) sind, so ist [X|Xs]
die Liste, die man erhält, wenn man das Element X an die Liste Xs
vorne anhängt.
Für X = a und Xs = [b,c,d] ist [X|Xs] = [a,b,c,d].
Listenzerlegung:Falls X und Xs ungebunden sind, so liefert der Aufruf [X|Xs] =
[a,b,c,d] die Belegungen X = a und Xs = [b,c,d]; man kann eine Liste
also in ihren Kopf X und den Rest Xs zerlegen.
leere Liste: [ ]
Prof. Dr. Dietmar Seipel 448
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Rekursion: das Prädikat member
/* member(?X, +L) <-
X is a member of the list L. */
member(X, [X|_]).
member(X, [_|Xs]) :-
member(X, Xs).
?- member(a, [c, b, a]).
Yes
Prof. Dr. Dietmar Seipel 449
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Relationales Programmieren
� � � � � � �� �� � � � � � � � �� �� � � � �� � �
?- member(b, [a, b, c]).
Yes
?- member(X, [a, b, c]).
X = a;
X = b;
X = c
Yes
Beim Aufruf member(X, Y) sind X und Y nicht funktional voneinander
abhängig. Stattdessen realisiert member/2 eine n:m–Beziehung (Relation)
zwischen Listen und ihren Elementen.
Prof. Dr. Dietmar Seipel 450
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Das Prädikat member/2 definiert eine virtuelle Relation:
member
Element List
a [a, b, c]
b [a, b, c]
c [a, b, c]
a [a, b]
Prof. Dr. Dietmar Seipel 451
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Suche in Graphen
� � � � _ �� �� � � � � �� � � � �� � � �� � � � �� � �
/* graph_search(+Node, -Path) <-
*/
graph_search(X, Path) :-
graph_search(X, [X], Path).
graph_search(X, _, [X]) :-
graph_sink(X).
graph_search(X, Visited, [X|Path]) :-
( graph_edge(X, Y)
; graph_edge(Y, X) ),
not(member(Y, Visited)),
write(user, ’->’), write(user, Y),
graph_search(Y, [Y|Visited], Path).
Prof. Dr. Dietmar Seipel 452
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Labyrinth:
�
�a b c
d e f
g h i
graph_edge(i, f).
graph_edge(i, h).
graph_edge(h, g).
graph_edge(g, d).
graph_edge(d, e).
graph_edge(d, a).
graph_edge(a, b).
graph_edge(b, c).
graph_source(i).
graph_sink(c).
Prof. Dr. Dietmar Seipel 453
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
?- graph_search(i, Path).
->f->h->g->d->e->a->b->c
Path = [i, h, g, d, a, b, c]
Yes
?- graph_search(e, Path).
->d->a->b->c
Path = [e, d, a, b, c] ;
->g->h->i->f
No
?-
Prof. Dr. Dietmar Seipel 454
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
� Das Prädikat graph_search/2 benutzt Tiefensuche, und es berechnet
einfache Pfade (ohne doppelte Knoten).
� Beim Aufruf graph_search(Node, Path) mit einem gebundenen
Argument Node und einem freien Argument Path können alle
einfache Pfade von Node zu einer Senke (graph_sink) über
Backtracking berechnet werden.
� Würde man eine weitere Kante graph_edge(e, b) in den Graphen
einfügen (die Wand zwischen e und b einreisen), so gäbe es einen
weiteren einfachen Pfad [e, b, c] von e zur Senke c.
Prof. Dr. Dietmar Seipel 455
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Man kann alle Antworten mittels Backtracking und findall/3 bestimmen:
...
graph_edge(e, b).
?- findall( Path,
graph_search(e, Path),
Paths ).
...
Paths = [ [e, d, a, b, c], [e, b, c] ]
Yes
?-
Prof. Dr. Dietmar Seipel 456
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Man kann mit PROLOG (im Gegensatz zur “reinen” Logikprogrammierung)
auch� prozedural
� mit Seiteneffekten und
� mit globalen Variablen (realisiert mit Hilfe von assert und retract)
programmieren.
Es gibt umfangreiche Programmbibliotheken und Erweiterungen:
� Datenstrukturen und Algorithmen, Kombinatorik,
� Datenbank– und Web–Programmierung,
� GUI–Programmierung, etc.
Prof. Dr. Dietmar Seipel 457
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Anwendungsbereiche:� regelbasierte Diagnosesysteme (Medizin, Technik)
� symbolische Informationsverarbeitung, Parsing
� Datenbanken mit komplexen Strukturen (Hierarchien, XML)
� Datenintegration
� Semantic Web
� Default Reasoning
� kombinatorische Suchprobleme
(Graphenprobleme, Spiele wie Sudoku oder Minesweeper, etc.)
Prof. Dr. Dietmar Seipel 458
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Quicksort in PROLOG
/* quicksort(List, Sorted_List) <-
*/
quicksort([], []) :-
!.
quicksort([X|Xs], Ys) :-
quicksort_divide(X, Xs, Xs1, Xs2),
quicksort(Xs1, Ys1),
quicksort(Xs2, Ys2),
append(Ys1, [X|Ys2], Ys).
Prof. Dr. Dietmar Seipel 459
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
quicksort_divide(X, Xs, Xs1, Xs2) :-
findall( X1,
( member(X1, Xs),
X1 < X ),
Xs1 ),
findall( X2,
( member(X2, Xs),
X2 > X ),
Xs2 ).
append([], Ys, Ys).
append([X|Xs], Ys, [X|Zs]) :-
append(Xs, Ys, Zs).
Prof. Dr. Dietmar Seipel 460
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Mergesort in PROLOG
/* mergesort(List, Sorted_List) <-
*/
mergesort(Xs, Xs) :-
length(Xs, N),
N =< 1,
!.
mergesort(Xs, Ys) :-
middle_split(Xs, Xs1, Xs2),
mergesort(Xs1, Ys1),
mergesort(Xs2, Ys2),
mergesort_merge(Ys1, Ys2, Ys).
Prof. Dr. Dietmar Seipel 461
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
mergesort_merge([], Xs, Xs) :-
!.
mergesort_merge(Xs, [], Xs) :-
!.
mergesort_merge([X1|Xs1], [X2|Xs2], [X|Xs]) :-
( X1 < X2,
X = X1,
mergesort_merge(Xs1, [X2|Xs2], Xs)
; X = X2,
mergesort_merge([X1|Xs1], Xs2, Xs) ).
Prof. Dr. Dietmar Seipel 462
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Binäre Suchbäume in PROLOG
/* search_in_binary_tree(Key, Tree) <-
*/
search_in_binary_tree(Key, Tree) :-
binary_tree_parse(Tree, Key, _, _).
search_in_binary_tree(Key, Tree) :-
binary_tree_parse(Tree, Root, Left, Right),
( ( Key < Root,
!,
Tree = Left )
; ( Key > Root,
Tree = Right ) ),
search_in_binary_tree(Key, Tree).
Prof. Dr. Dietmar Seipel 463
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Kapselung des Zugriffs:
/* binary_tree_empty(Tree) <-
*/
binary_tree_empty(Tree) :-
( dislog_variable_get(binary_tree_mode, xml),
Tree = node:[]:[]
; Tree = [] ).
Prof. Dr. Dietmar Seipel 464
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
/* binary_tree_parse(Tree, Key, Lson, Rson) <-
*/
binary_tree_parse(Tree, Key, Empty, Empty) :-
binary_tree_empty(Empty),
( dislog_variable_get(binary_tree_mode, xml),
Tree = node:[key:Key]:[]
; Tree = [Key] ),
!.
binary_tree_parse(Tree, Key, Lson, Rson) :-
( dislog_variable_get(binary_tree_mode, xml),
Tree = node:[key:Key]:[Lson, Rson]
; Tree = [Key, Lson, Rson] ).
Prof. Dr. Dietmar Seipel 465
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Suchbaum in XML–Darstellung:
<node key="8">
<node key="4">
<node key="2">
<node key="1"/>
<node key="3"/>
</node>
<node key="6">
<node key="5"/>
<node key="7"/>
</node>
</node>
<node key="12">
<node key="10">
<node key="9"/>
<node key="11"/>
</node>
<node key="13"/>
</node>
</node>
Prof. Dr. Dietmar Seipel 466
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
Suchbaum
XML–Darstellung:
<node key="2">
<node key="1"/>
<node key="3"/>
</node>
PROLOG–Darstellung:
node:[key:2]:[
node:[key:1],
node:[key:3] ]
alternative PROLOG–Darstellung:
[ 2,
[1],
[3] ]
Prof. Dr. Dietmar Seipel 467
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
/* insert_into_binary_tree(Key, Tree, New_Tree) <-
*/
insert_into_binary_tree(Key, Tree, New_Tree) :-
binary_tree_parse(Tree, Root, Left, Right),
( ( Key = Root, % Key is already in Tree
New_Tree = Tree )
; ( Key < Root,
insert_into_binary_tree(Key, Left, L),
binary_tree_parse(New_Tree, Root, L, Right) )
; ( Key > Root,
insert_into_binary_tree(Key, Right, R),
binary_tree_parse(New_Tree, Root, Left, R) ) ).
insert_into_binary_tree(Key, Tree, New_Tree) :-
binary_tree_empty(Tree),
binary_tree_parse(New_Tree, Key, Tree, Tree).
Prof. Dr. Dietmar Seipel 468
Praktische Informatik I – Algorithmen und Datenstrukturen Wintersemester 2006/07
/* keys_to_binary_tree(Keys, Tree) <-
*/
keys_to_binary_tree(Keys, Tree) :-
binary_tree_empty(Empty),
insert_into_binary_tree_(Keys, Empty, Tree).
/* insert_into_binary_tree_(Keys, Tree, New_Tree) <-
*/
insert_into_binary_tree_([], Tree, Tree).
insert_into_binary_tree_([Key|Keys], Tree, New_Tree) :-
insert_into_binary_tree(Key, Tree, Tree_2),
insert_into_binary_tree_(Keys, Tree_2, New_Tree).
Prof. Dr. Dietmar Seipel 469