Listen und Akkumulatoren
Weitere Beispiele zur Listenmanipulation Akkumulatoren zur Effizienzsteigerung Nicht-deterministischer Automat
Quicksort mit Prolog
Weitere Beispiele zur Listenmanipulation Akkumulatoren zur Effizienzsteigerung Nicht-deterministischer Automat
Quicksort mit Prolog
Ein Element an eine Liste
anhängen, ein Element löschen
add(X,L[X|L]).
Das neue Element ist einfach der neue Kopf.
del(X,L,L1)
(1) ist X der Kopf, einfacher Fall del(X,[X|Tail],Tail)
(2) ist X in Tail wird es dort gelöscht
del(X,[Y|Tail],[Y|TailL1]):- del(X,Tail, TailL1).
del ergibt fail, wenn das zu löschende Element nicht in der Liste ist über backtracking können alle anderen Elemente X aus der Liste gelöscht werden (immer nur eins, nicht alle). del kann auch dazu benutzt werden ein Element an einer beliebigen Stelle in die Liste einzufügen.
?- del(a,L,[1,2,3])
durch backtracking wird 'a' nach hinten durchgereicht.
insert(X,List, BiggerList) :- del(X,BiggerList, List).
add(X,L[X|L]).
Das neue Element ist einfach der neue Kopf.
del(X,L,L1)
(1) ist X der Kopf, einfacher Fall del(X,[X|Tail],Tail)
(2) ist X in Tail wird es dort gelöscht
del(X,[Y|Tail],[Y|TailL1]):- del(X,Tail, TailL1).
del ergibt fail, wenn das zu löschende Element nicht in der Liste ist über backtracking können alle anderen Elemente X aus der Liste gelöscht werden (immer nur eins, nicht alle). del kann auch dazu benutzt werden ein Element an einer beliebigen Stelle in die Liste einzufügen.
?- del(a,L,[1,2,3])
durch backtracking wird 'a' nach hinten durchgereicht.
insert(X,List, BiggerList) :- del(X,BiggerList, List).
Ein Element löschen
loesche(X,[X|L],L).
loesche(X,[Y|L],[Y|L1]):- loesche(X,L,L1).
[trace] ?- loesche(1,[1,2,1,3],L).
Call: (7) loesche(1, [1, 2, 1, 3], _G9797) ? creep Exit: (7) loesche(1, [1, 2, 1, 3], [2, 1, 3]) ? creep L = [2, 1, 3] ;
Redo: (7) loesche(1, [1, 2, 1, 3], _G9797) ? creep Call: (8) loesche(1, [2, 1, 3], _G9876) ? creep Call: (9) loesche(1, [1, 3], _G9879) ? creep Exit: (9) loesche(1, [1, 3], [3]) ? creep Exit: (8) loesche(1, [2, 1, 3], [2, 3]) ? creep Exit: (7) loesche(1, [1, 2, 1, 3], [1, 2, 3]) ? creep L = [1, 2, 3] ;
Durch Backtracking werden konsekutiv die 1en gelöscht
loesche(X,[X|L],L).
loesche(X,[Y|L],[Y|L1]):- loesche(X,L,L1).
[trace] ?- loesche(1,[1,2,1,3],L).
Call: (7) loesche(1, [1, 2, 1, 3], _G9797) ? creep Exit: (7) loesche(1, [1, 2, 1, 3], [2, 1, 3]) ? creep L = [2, 1, 3] ;
Redo: (7) loesche(1, [1, 2, 1, 3], _G9797) ? creep Call: (8) loesche(1, [2, 1, 3], _G9876) ? creep Call: (9) loesche(1, [1, 3], _G9879) ? creep Exit: (9) loesche(1, [1, 3], [3]) ? creep Exit: (8) loesche(1, [2, 1, 3], [2, 3]) ? creep Exit: (7) loesche(1, [1, 2, 1, 3], [1, 2, 3]) ? creep L = [1, 2, 3] ;
Durch Backtracking werden konsekutiv die 1en gelöscht
Sublist
S ist eine Subliste von L wenn
(1) L in zwei Listen L1 und L2 zerlegt werden kann (2) L2 in S und eine Liste L3 zerlegt werden kann.
sublist(S,L):- append(L1,L2,L), append(S,L3,L2).
?- sublist([c,d,e],[a,b,c,d,e,f])
?- sublist([c,e][a,b,c,d,e,f])
generiere "alle" Sublisten: ?- sublist(S,[a,b,c]).
ausprobieren: übergeneriert z.B. [ ] zweimal, warum?
S ist eine Subliste von L wenn
(1) L in zwei Listen L1 und L2 zerlegt werden kann (2) L2 in S und eine Liste L3 zerlegt werden kann.
sublist(S,L):- append(L1,L2,L), append(S,L3,L2).
?- sublist([c,d,e],[a,b,c,d,e,f])
?- sublist([c,e][a,b,c,d,e,f])
generiere "alle" Sublisten: ?- sublist(S,[a,b,c]).
ausprobieren: übergeneriert z.B. [ ] zweimal, warum?
Permutationen
Zweistelliges Prädikat, ein Argument ist die Ausgangsliste, das andere die permutierte Variante.
(1) wenn die erste Liste leer ist, muss die zweite auch leer sein
(2) wenn die erste Liste nicht leer ist, so hat sie die Form [X|L] und eine Permutation kann wie folgt erstellt werden: erstelle erst eine permutation L1 von L (rekursiver Aufruf) und füge dann X an jeder Stelle von L1 ein um jeweils eine andere Permutation zu erhalten.
Zweistelliges Prädikat, ein Argument ist die Ausgangsliste, das andere die permutierte Variante.
(1) wenn die erste Liste leer ist, muss die zweite auch leer sein
(2) wenn die erste Liste nicht leer ist, so hat sie die Form [X|L] und eine Permutation kann wie folgt erstellt werden: erstelle erst eine permutation L1 von L (rekursiver Aufruf) und füge dann X an jeder Stelle von L1 ein um jeweils eine andere Permutation zu erhalten.
L
L1 X
permutiere L zu L1
füge X in L1 ein
Permutationen
pemutation([ ],[ ]).
pemutation([X|L],P):- permutation(L,L1), insert(X,L1,P).
oder alternativ: lösche ein Element X von der ersten Liste, permutiere den Rest zu P und füge X am Beginn von P ein.
pemutation2([ ],[ ]).
pemutation2(L,[X|P]):- del(X,L,L1), permutation2(L1,P).
?- permutation([red,blue,green],P).
P=[red,blue,green]
P=[red,green,blue]
P=[blue,red,green]
...
pemutation([ ],[ ]).
pemutation([X|L],P):- permutation(L,L1), insert(X,L1,P).
oder alternativ: lösche ein Element X von der ersten Liste, permutiere den Rest zu P und füge X am Beginn von P ein.
pemutation2([ ],[ ]).
pemutation2(L,[X|P]):- del(X,L,L1), permutation2(L1,P).
?- permutation([red,blue,green],P).
P=[red,blue,green]
P=[red,green,blue]
P=[blue,red,green]
...
Akkumulatoren
Die bisherigen Beispiele zur rekursiven Programmierung konnten keine Zwischenergebnisse mitführen. Der Wert eines rekursiven Aufrufs war unabhängig vom Kontext.
Beispiel umkehren einer Liste = Reihenfolge der Elemente umdrehen.
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
%X rutscht von vorne nach hinten
Die bisherigen Beispiele zur rekursiven Programmierung konnten keine Zwischenergebnisse mitführen. Der Wert eines rekursiven Aufrufs war unabhängig vom Kontext.
Beispiel umkehren einer Liste = Reihenfolge der Elemente umdrehen.
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
%X rutscht von vorne nach hinten
Akkumulatoren
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
Wie lange wird reverse rekursiv aufgerufen? Bis die Eingangsliste beim letzten Element angekommen ist: L ist leer und X ist 4!
Dann matcht reverse([ ],[ ]). Es ergibt sich RL ist [ ].
append wird zum ersten mal aufgerufen: [ ] wird an X angehängt.
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
Wie lange wird reverse rekursiv aufgerufen? Bis die Eingangsliste beim letzten Element angekommen ist: L ist leer und X ist 4!
Dann matcht reverse([ ],[ ]). Es ergibt sich RL ist [ ].
append wird zum ersten mal aufgerufen: [ ] wird an X angehängt.
Akkumulatoren
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
die Ausgabeliste des ersten append Aufrufs ist [x].
Vorletzer rekursiver Aufruf(Aufstieg).
reverse([3|4],R)
reverse(L=[4], RL = [4]) und damit wird append mit append([4],[3],R) aufgerufen und R wird: [4,3].
und so weiter und sofort. Aufgabe: machen Sie sich den ganzen Aufstieg klar, bis die Liste umgedreht ist.
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
die Ausgabeliste des ersten append Aufrufs ist [x].
Vorletzer rekursiver Aufruf(Aufstieg).
reverse([3|4],R)
reverse(L=[4], RL = [4]) und damit wird append mit append([4],[3],R) aufgerufen und R wird: [4,3].
und so weiter und sofort. Aufgabe: machen Sie sich den ganzen Aufstieg klar, bis die Liste umgedreht ist.
Akkumulatoren
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
was ist der Nachteil dieser Vorgehensweise:
append ist linear wird aber für jedes Element der Liste wieder aufgerufen: insgesamt wird der Aufwand für reverse quadratisch (Details im Leiss-Skript Seite 20/21).
Implementation mit Akkumulator:
● Staple die Elemente der Eingabeliste auf eine Liste von Zwischenergebnissen(=Akkumulator)
● Beginne mit dem leeren Stapel
● Gib den Stapel aus, wenn die Eingabeliste leer ist
[1,2,3,4] → [4,3,2,1]
Mit append:
reverse([ ],[ ]).
reverse([X|L],R) :-
reverse(L,RL), append(RL,[X ],R).
was ist der Nachteil dieser Vorgehensweise:
append ist linear wird aber für jedes Element der Liste wieder aufgerufen: insgesamt wird der Aufwand für reverse quadratisch (Details im Leiss-Skript Seite 20/21).
Implementation mit Akkumulator:
● Staple die Elemente der Eingabeliste auf eine Liste von Zwischenergebnissen(=Akkumulator)
● Beginne mit dem leeren Stapel
● Gib den Stapel aus, wenn die Eingabeliste leer ist
Reverse mit Akkumulator
reverse(L,R) :- reverse_acc(L,[ ],R).
reverse_acc([X|L],Acc,R):- reverse_acc(L,[X|Acc],R).
reverse_acc([],Acc,Acc).
Die Eingabeliste [1,2,3,4] wird der Reihe nach geköpft und auf den Akkumulator geschrieben.
Wenn die Liste leer ist wird der Akkumulator auf die Ausgabeliste geschoben und diese nach oben durchgereicht bis schliesslich das zweistellige Aufrufprädikat reverse erreicht wird.
Der Algorithmus ist linear in der Größe der Eingabe. Aufgabe:
machen Sie sich klar warum
reverse(L,R) :- reverse_acc(L,[ ],R).
reverse_acc([X|L],Acc,R):- reverse_acc(L,[X|Acc],R).
reverse_acc([],Acc,Acc).
Die Eingabeliste [1,2,3,4] wird der Reihe nach geköpft und auf den Akkumulator geschrieben.
Wenn die Liste leer ist wird der Akkumulator auf die Ausgabeliste geschoben und diese nach oben durchgereicht bis schliesslich das zweistellige Aufrufprädikat reverse erreicht wird.
Der Algorithmus ist linear in der Größe der Eingabe. Aufgabe:
machen Sie sich klar warum
Anzahl der Elemente einer Liste
Lösung ohne Akkumulator:
len([ ],0).
len([H|T],N) :-
len(T,N1) , N is N1 +1.
Aufgabe: denken Sie darüber nach, wie das Programm für die Liste [1,2,3,4] abläuft.
Das rekursive Prädikat köpft die Liste und ruft mit der Restliste rekursiv auf.
Die Rekursion stoppt, wenn T = [ ] und somit N1 = 0.
Damit wird N für den letzten rekursiven Aufruf 1.
Bedeutet das, dass schon die leere Liste Länge 1 hat?
Lösung ohne Akkumulator:
len([ ],0).
len([H|T],N) :-
len(T,N1) , N is N1 +1.
Aufgabe: denken Sie darüber nach, wie das Programm für die Liste [1,2,3,4] abläuft.
Das rekursive Prädikat köpft die Liste und ruft mit der Restliste rekursiv auf.
Die Rekursion stoppt, wenn T = [ ] und somit N1 = 0.
Damit wird N für den letzten rekursiven Aufruf 1.
Bedeutet das, dass schon die leere Liste Länge 1 hat?
Anzahl der Elemente einer Liste
Lösung mit Akkumulator:
len2(L,N,) :- lenacc(L,0,N).
lenacc([],Acc,Acc).
lenacc([H|T],Acc,N) :-
Acc1 is Acc +1, lenacc(T,Acc1,N).
Klarmachen: der neue Aufruf hat jeweils um 1 erhöhtem Akkumulator und um 1 verkürzte Liste.
In prozeduralen Programmiersprachen arbeitet man mit Iteration und einer Variablen , die Skopus über die gesamte Iteration hat. In Prolog wird eine Hilfsvariable mit einem Startwert mitgeführt die jeweils an den nächsten rekursiven Aufruf übergeben wird. Bei Ende der
Rekursion steht das Ergebnis unmittelbar in der Hilfsvariablen.
Lösung mit Akkumulator:
len2(L,N,) :- lenacc(L,0,N).
lenacc([],Acc,Acc).
lenacc([H|T],Acc,N) :-
Acc1 is Acc +1, lenacc(T,Acc1,N).
Klarmachen: der neue Aufruf hat jeweils um 1 erhöhtem Akkumulator und um 1 verkürzte Liste.
In prozeduralen Programmiersprachen arbeitet man mit Iteration und einer Variablen , die Skopus über die gesamte Iteration hat. In Prolog wird eine Hilfsvariable mit einem Startwert mitgeführt die jeweils an den nächsten rekursiven Aufruf übergeben wird. Bei Ende der
Rekursion steht das Ergebnis unmittelbar in der Hilfsvariablen.
Nicht-deterministischer Automat vgl. Bratko S.94ff
Eine abstrakte Maschine, die Input einliest, etwa einen String von Symbolen und die
● Entscheidet einen String abzulehnen oder zu akzeptieren
● Eine Reihe von Zuständen hat und immer in einem Zustand ist
● Von einem Zustand in den andern gehen kann
● Deren interne Struktur als Transitionsgraph repräsentiert werden kann
Eine abstrakte Maschine, die Input einliest, etwa einen String von Symbolen und die
● Entscheidet einen String abzulehnen oder zu akzeptieren
● Eine Reihe von Zuständen hat und immer in einem Zustand ist
● Von einem Zustand in den andern gehen kann
● Deren interne Struktur als Transitionsgraph repräsentiert werden kann
Nicht-deterministischer Automat vgl. Bratko S.94ff
S3 S2
S4 a
b a
null null b S1
Nicht-deterministischer Automat vgl. Bratko S.94ff
Der Automat akzeptiert einen String wenn:
(1) er startet in irgendeinem Initialzustand (2) er endet in einem Finalzustand
(3) die Übergangslabels auf dem Pfad korrespondieren mit dem gesamten Inputstring
Automatenrepräsentation in Prolog:
(a) unäre Relation final(S3)
(b) 3-stellige Übergangsrelation trans(S1,X,S2) (c) binäre Übergangsrelation silent(S1,S2)
Der Automat akzeptiert einen String wenn:
(1) er startet in irgendeinem Initialzustand (2) er endet in einem Finalzustand
(3) die Übergangslabels auf dem Pfad korrespondieren mit dem gesamten Inputstring
Automatenrepräsentation in Prolog:
(a) unäre Relation final(S3)
(b) 3-stellige Übergangsrelation trans(S1,X,S2) (c) binäre Übergangsrelation silent(S1,S2)
Nicht-deterministischer Automat vgl. Bratko S.94ff
Beispiel aus dem Übergangsgraphen final(s3).
trans(s1,a,s1).
trans(s1,a,s2).
trans(s1,b,s1).
trans(s2,b,s3).
trans(s3,b,s4).
silent(s2,s4).
silent(s3,s1).
Inputstrings werden als Prologlisten etwa [a,a,b] übergeben
Beispiel aus dem Übergangsgraphen final(s3).
trans(s1,a,s1).
trans(s1,a,s2).
trans(s1,b,s1).
trans(s2,b,s3).
trans(s3,b,s4).
silent(s2,s4).
silent(s3,s1).
Inputstrings werden als Prologlisten etwa [a,a,b] übergeben
Nicht-deterministischer Automat vgl. Bratko S.94ff
accept Prädikat für Zustand State
(1) leerer String wird akzeptiert, wenn für den Zustand State des Automaten final zutrifft
(2) ein nicht-leerer String wird akzeptiert, wenn nach dem Lesen des ersten Symbols ein Zustand State1 erreicht wird, von dem aus der Reststring akzeptiert wird
(3) ein nicht-leerer String wird akzeptiert, wenn durch einen silent move (Spontanübergang) ein State1 erreicht wird, von dem aus der String akzeptiert wird
accept Prädikat für Zustand State
(1) leerer String wird akzeptiert, wenn für den Zustand State des Automaten final zutrifft
(2) ein nicht-leerer String wird akzeptiert, wenn nach dem Lesen des ersten Symbols ein Zustand State1 erreicht wird, von dem aus der Reststring akzeptiert wird
(3) ein nicht-leerer String wird akzeptiert, wenn durch einen silent move (Spontanübergang) ein State1 erreicht wird, von dem aus der String akzeptiert wird
Nicht-deterministischer Automat vgl. Bratko S.94ff
accept(State,[ ]) :- final(State).
accept(State[X|Reststring]) :- trans(State,X,State1),
accept(State1,Reststring).
accept(State,String) :- silent(State,State1), accept(State1,String).
accept(State,[ ]) :- final(State).
accept(State[X|Reststring]) :- trans(State,X,State1),
accept(State1,Reststring).
accept(State,String) :- silent(State,State1), accept(State1,String).
first restX null string
Nicht-deterministischer Automat vgl. Bratko S. 94ff
Anwendungen
Entscheide eine Eingabe
?- accept(S1,[a,a,a,b]) yes.
Gib alle akzeptierten Strings der Länge 3 von s1 als Startzustand aus – Teilsprache des Automaten.
?- accept(s1,[X1,X2,X3]).
X1=a X2=a X3 =b;
X1=b X2=a X3 =b;
no.
?- String=[_,_,_], accept(s1,String).
Ausgabe?
Anwendungen
Entscheide eine Eingabe
?- accept(S1,[a,a,a,b]) yes.
Gib alle akzeptierten Strings der Länge 3 von s1 als Startzustand aus – Teilsprache des Automaten.
?- accept(s1,[X1,X2,X3]).
X1=a X2=a X3 =b;
X1=b X2=a X3 =b;
no.
?- String=[_,_,_], accept(s1,String).
Ausgabe?
Quicksort
Klassischer sehr effizienter Sortieralgorithmus nach dem Prinzip
„teile und herrsche“. (vgl. Skript Hans Leiss, S. 22)
Sortiere eine Liste L von Zahlen nach ihrer Größe zu L' (i) Wähle ein Element aus X
(ii) Zerlege L in eine Liste Bigger, in der alle Elemente Y>= X und eine Liste Smaller, in der alle Elemente Y < X
(iii) Sortiere die Listen Bigger und Smaller nach dem gleichen Prinzip (Rekursion)
(iv) Bilde L' durch append(Bigger', [X|Smaller'],L')
Klassischer sehr effizienter Sortieralgorithmus nach dem Prinzip
„teile und herrsche“. (vgl. Skript Hans Leiss, S. 22)
Sortiere eine Liste L von Zahlen nach ihrer Größe zu L' (i) Wähle ein Element aus X
(ii) Zerlege L in eine Liste Bigger, in der alle Elemente Y>= X und eine Liste Smaller, in der alle Elemente Y < X
(iii) Sortiere die Listen Bigger und Smaller nach dem gleichen Prinzip (Rekursion)
(iv) Bilde L' durch append(Bigger', [X|Smaller'],L')
Quicksort
quicksort([ ],[ ]).
quicksort([ X|Xs],Ys):- partition(X,Xs,Big,Small), quicksort(Big,Bs),
quicksort(Small,Ss), append(Bs,[X|Ss],Ys).
quicksort([ ],[ ]).
quicksort([ X|Xs],Ys):- partition(X,Xs,Big,Small), quicksort(Big,Bs),
quicksort(Small,Ss), append(Bs,[X|Ss],Ys).
Quicksort
partition(_,[ ],[ ],[ ]).
partition(X,[Z|Zs], ZsBig, [Z|ZsSmall]) :-
Z<X, partition(X,Zs, ZsBig, ZsSmall).
partition(X,[Z|Zs], [Z|ZsBig], ZsSmall) :-
Z>=X, partition(X,Zs, ZsBig, ZsSmall).
Beispielaufruf: quicksort wird mit [2,4,3,1] gestartet:
1. Aufruf partition(2,[4,3,1],Big,Small).
Da 4 >= 2 matcht 3. partition Regel
2. (rekursiver) Aufruf: partition(2,[3,1],ZsBig,ZsSmall)
Liste Big wird zusammengebaut wenn Rekursion zurückkehrt und Tail ZsBig belegt.
Da 3>= 2 matcht wieder die 3. Regel
3. (rekursiver) Aufruf: partition(2,[1],ZsBig,ZsSmall) Da 1 < 2 matcht 2. Regel.
4. (rekursver) Aufruf: partition(2,[],ZB,ZS).
Da Verarbeitungsliste leer ist matcht die 1. Regel.
Zusammenbau erfolgt und Big wird mit [4,3] Small mit [1] an Quicksort zurückgegeben.
partition(_,[ ],[ ],[ ]).
partition(X,[Z|Zs], ZsBig, [Z|ZsSmall]) :-
Z<X, partition(X,Zs, ZsBig, ZsSmall).
partition(X,[Z|Zs], [Z|ZsBig], ZsSmall) :-
Z>=X, partition(X,Zs, ZsBig, ZsSmall).
Beispielaufruf: quicksort wird mit [2,4,3,1] gestartet:
1. Aufruf partition(2,[4,3,1],Big,Small).
Da 4 >= 2 matcht 3. partition Regel
2. (rekursiver) Aufruf: partition(2,[3,1],ZsBig,ZsSmall)
Liste Big wird zusammengebaut wenn Rekursion zurückkehrt und Tail ZsBig belegt.
Da 3>= 2 matcht wieder die 3. Regel
3. (rekursiver) Aufruf: partition(2,[1],ZsBig,ZsSmall) Da 1 < 2 matcht 2. Regel.
4. (rekursver) Aufruf: partition(2,[],ZB,ZS).
Da Verarbeitungsliste leer ist matcht die 1. Regel.
Zusammenbau erfolgt und Big wird mit [4,3] Small mit [1] an Quicksort zurückgegeben.
Quicksort mit Akkumulator
Spare append Aufrufe: akkumuliere alle schon gesehenen Eingabeelemente auf dem Akkumulator
quicksort(Xs,Ys):- quicksort_acc(Xs,[ ],Ys).
quicksort_acc([ X|Xs],Acc,Ys):- partition(X,Xs,Big,Small), quicksort_acc(Big,Acc,Zs),
quicksort_acc(Small,[X|Zs],Ys).
%Implementierung partition bleibt gleich
Spare append Aufrufe: akkumuliere alle schon gesehenen Eingabeelemente auf dem Akkumulator
quicksort(Xs,Ys):- quicksort_acc(Xs,[ ],Ys).
quicksort_acc([ X|Xs],Acc,Ys):- partition(X,Xs,Big,Small), quicksort_acc(Big,Acc,Zs),
quicksort_acc(Small,[X|Zs],Ys).
%Implementierung partition bleibt gleich
Hausaufgabe
(1) In den Skripten Hadersbeck und Leiss den Stand der Vorlesung verifizieren (Tipp: Hadersbeckskript, S.35)
(2) In Bratko Kapitel 4 lesen, versuchen Sie alle 4 dargestellten Probleme und deren Lösung in Prolog zu verstehen.
(3) Implementieren Sie die Programme für den Automaten und Quicksort und probieren Sie sie aus.
(1) In den Skripten Hadersbeck und Leiss den Stand der Vorlesung verifizieren (Tipp: Hadersbeckskript, S.35)
(2) In Bratko Kapitel 4 lesen, versuchen Sie alle 4 dargestellten Probleme und deren Lösung in Prolog zu verstehen.
(3) Implementieren Sie die Programme für den Automaten und Quicksort und probieren Sie sie aus.