• Keine Ergebnisse gefunden

Listen und Akkumulatoren

N/A
N/A
Protected

Academic year: 2022

Aktie "Listen und Akkumulatoren"

Copied!
25
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

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

(2)

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).

(3)

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

(4)

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?

(5)

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

(6)

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]

...

(7)

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

(8)

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.

(9)

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.

(10)

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

(11)

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

(12)

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?

(13)

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.

(14)

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

(15)

Nicht-deterministischer Automat vgl. Bratko S.94ff

S3 S2

S4 a

b a

null null b S1

(16)

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)

(17)

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

(18)

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

(19)

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

(20)

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?

(21)

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')

(22)

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).

(23)

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.

(24)

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

(25)

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.

Referenzen

ÄHNLICHE DOKUMENTE

Our main contribution is to demonstrate and resolve this issue by showing that iterative application of any permutation algorithm, whose corresponding permutation matrix is

Eine Matrix P ist genau dann eine Permutationsmatrix, wenn in jeder Spalte und in jeder Zeile genau eine 1 steht, sonst sind die Eintr¨age 02. Eine Permutationsmatrix hat

Aus einer Urne mit 2 roten und 2 schwarzen Kugeln werden nacheinander 3 Kugeln entnommen, wobei jede mögliche Auswahl von 3 Kugel die gleiche Wahrscheinlichkeit besitzen soll.. A

[r]

Wieviele nat¨ urliche Zahlen gibt es zwischen 1 und 1 000 000, die weder eine Quadratzahl, noch eine Kubikzahl, noch eine vierte Potenz

Diffusion Die Diffusion einer Blockchiffre ist groß, wenn jedes Bit des Klartextes und jedes Bit des Schlüssels möglichst viele Bits des Chiffretexts beeinflusst.. Entschlüsselung

This example does not show that dynamic hill climbing is a better algorithm than others, its only purpose is to show that by using this approach we allow techniques that can only

14.1) Gegeben sei ein kreisfreier Graph mit den Knoten 1 -7. Mit ausgelöstem Backtracking sollen alle Pfade im Graphen ausgegeben werden können. Es hilft, wenn Sie den