Rekursion und EBNF Flashcards

1
Q

Was bedeutet es, wenn eine Funktion rekursiv definiert ist?

A

Ist eine Funktion rekursiv definiert, so erscheint die Funktion in ihrer eigenen Definition, z.B.:

πš’πš—πš πšπšŠπš”πšžπš•πšπšŠπšŽπš(πš’πš—πš πš—) {
  πš’πš (πš— <= 𝟷)
    πš›πšŽπšπšžπš›πš— 𝟷;
  πšŽπš•πšœπšŽ
    πš›πšŽπšπšžπš›πš— πš— * πšπšŠπš”πšžπš•πšπšŠπšŽπš(πš—-𝟷);
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Was ist ein mΓΆgliches Problem rekursiv definierter Funktionen und wie lΓ€sst sich dieses umgehen?

A

Rekursive Funktionen kΓΆnnen in einer unendlichen Rekursion enden, z.B.: πšŸπš˜πš’πš 𝚏() {𝚏()}.
Man braucht also einen garantierten Fortschritt in Richtung einer Abbruchbedingung, z.B. bei folgendem Code…
πš’πš—πš πšπšŠπš”πšžπš•πšπšŠπšŽπš(πš’πš—πš πš—) {
πš’πš (πš— <= 𝟷)
πš›πšŽπšπšžπš›πš— 𝟷;
πšŽπš•πšœπšŽ
πš›πšŽπšπšžπš›πš— πš— * πšπšŠπš”πšžπš•πšπšŠπšŽπš(πš—-𝟷);
}
…endet die Rekursion, falls n ≀ 1 und es entsteht ein neuer rekursiver Aufruf mit einem Argument kleiner n.
Die Abbruchbedingung wird daher garantiert erreicht.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Wie wird eine rekursive Funktion ausgewertet?

A

Bei jedem Funktionsaufruf kommt der Wert des Aufrufarguments auf einen Stapel und es wird immer mit dem obersten Wert des Stapels gearbeitet.
Am Ende eines Aufrufs wird der oberste Wert wieder vom Stapel gelΓΆscht.

(Gutes Bild in PPT-Slides von 05.11.2019!)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Betrachte folgenden Codeausschnitt:

πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš πšπš’πš‹(πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš πš—) {
  πš’πš (πš— == 0) πš›πšŽπšπšžπš›πš— 0; 
  πš’πš (πš— == 𝟷) πš›πšŽπšπšžπš›πš— 𝟷; 
  πš›πšŽπšπšžπš›πš— πšπš’πš‹(πš—-𝟷) + πšπš’πš‹(πš—-𝟸);
}

Wo liegt hier das Problem und wie kann es behoben werden?

A

Der Code funktioniert gut fΓΌr kleine Zahlen, fΓΌr grosse Zahlen jedoch dauert die Berechnung viel zu lange.

FΓΌr πšπš’πš‹(𝟻0) z.B. wird Fβ‚„β‚ˆ 2-mal, F₄₇ 3-mal, F₄₆ 5-mal, Fβ‚„β‚… 8-mal, Fβ‚„β‚„ 13-mal, F₄₃ 21-mal und F₁ eine Milliarde mal berechnet!
Um dies zu verbessern, schaut man, dass jede Zahl nur einmal berechnet wird und jeweils nur die letzten beiden berechneten Werte gespeichert werden.
Eine LΓΆsung wΓ€re z.B. folgender Codeausschnitt:

πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš πšπš’πš‹(πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš πš—) {
πš’πš (πš— == 0) πš›πšŽπšπšžπš›πš— 0;
πš’πš (πš— == 𝟷) πš›πšŽπšπšžπš›πš— 𝟷;

πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš 𝚊 = 0;
πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš πš‹ = 𝟷;

  πšπš˜πš› (πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš πš’ = 𝟸; πš’ <= πš—; ++πš’) {
    πšžπš—πšœπš’πšπš—πšŽπš πš’πš—πš 𝚊_πš˜πš•πš = 𝚊;
    𝚊 = πš‹;
    πš‹ += 𝚊_πš˜πš•πš;
  }
  πš›πšŽπšπšžπš›πš— πš‹;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Welche anderen zwei β€œMethoden” kann man anstelle einer rekursiven Funktion verwenden?

A

Eine Rekursion kann immer simuliert werden durch…

(1) … Iteration (Schleifen).
(2) … expliziten β€œAufrufstapeln” (z.B. mit einem Vektor).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Betrachte folgenden Codeausschnitt zur Berechnung einfacher arithmetischer Operationen:

πšπš˜πšžπš‹πš•πšŽ πš•πšŸπšŠπš•;
𝚜𝚝𝚍::πšŒπš’πš—&raquo_space; πš•πšŸπšŠπš•;

πšŒπš‘πšŠπš› πš˜πš™; 
πš πš‘πš’πš•πšŽ (𝚜𝚝𝚍::πšŒπš’πš— >> πš˜πš™ &amp;&amp; πš˜πš™ != ’=’) { 
  πšπš˜πšžπš‹πš•πšŽ πš›πšŸπšŠπš•; 
  𝚜𝚝𝚍::πšŒπš’πš— >> πš›πšŸπšŠπš•;
  πš’πš (πš˜πš™ == ’+’) 
    πš•πšŸπšŠπš• += πš›πšŸπšŠπš•; 
  πšŽπš•πšœπšŽ πš’πš (πš˜πš™ == ’*’) 
    πš•πšŸπšŠπš• *= πš›πšŸπšŠπš•; 
  πšŽπš•πšœπšŽ ...
} 
𝚜𝚝𝚍::𝚌𝚘𝚞𝚝 << "π™΄πš›πšπšŽπš‹πš—πš’πšœ " << πš•πšŸπšŠπš• << "\πš—";

Wo kommt es hier zum Problem und weshalb ist es nicht so einfach, dieses Problem zu lΓΆsen?

A

Die PrΓ€zedenzen werden nicht eingehalten: Der Code lΓ€sst mehrfache Operationen hintereinander zu (durch die while-Schlaufe), z.B. 3 + 2 * 4 oder 1 + 1 * 2 + 2 * … .
Jedoch wird das Ergebnis falsch sein, wenn Punkt- und Strichrechnung gemischt wird, da lediglich die LinksprΓ€zedenz eingehalten wird mit diesem Code.
Da die LΓΆsung dieses Problems erfordert, dass der Code alle noch folgenden PrΓ€zedenzen kennt (*), braucht man ein neues formales (von C++ unabhΓ€ngiges) Handwerkszeug (= Grammatiken).

(*) z.B. muss das Programm, um 13 + 4 * (15 - 7 * 3) zu berechnen, bis zur "3" am Ende der Rechnung alle Werte zwischenspeichern, da es aufgrund der Teilrechnungen nie weiss, ob noch ein Schritt folgt oder nicht:
13 + …?
13 + 4 * …?
13 + 4 * (15 - …?
13 + 4 * (15 - 7 * …?
13 + 4 * (15 - 7 * 3) !
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Was ist ein terminales Symbol bzw. ein nicht terminales Symbol und wo werden diese Symbole gebraucht?

A

Ein terminales Symbol ist ein Symbol, z.B. β€˜8’, welches nicht weiter gekΓΌrzt werden kann.
Ein nicht-terminales Symbol kann durch erneute Berechnung eines rekursiven Funktionsaufrufs immer wieder verwendet werden und entsprechend gekΓΌrzt werden.
Man braucht diese Symbole folglich in rekursiven Funktionen.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Wie kann man den Begriff β€œZahl” mit Hilfe des Begriffs β€œZiffer” definieren, und zwar…

(1) … rekursiv?
(2) … nicht rekursiv?

A

(1) Eine Zahl ist eine Folge von Ziffern. Eine Folge von Ziffern ist:
- nur eine Ziffer (z.B. β€œ2”), oder
- eine Ziffer gefolgt von einer Folge von Ziffern (z.B. β€œ2019”).
Man sieht hier, dass β€œFolge von Ziffern” mit β€œFolge von Ziffern” definiert wird, also rekursiv.

(2) Eine Zahl ist eine Folge von Ziffern. Eine Folge von Ziffern ist:
- nur eine Ziffer (z.B. β€œ2”), oder
- eine Ziffer gefolgt von beliebig vielen Ziffern (z.B. β€œ2019”).
Man sieht hier, dass β€œFolge von Ziffern” nur mit der Definition von β€œZiffer” auskommt, also nicht rekursiv.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Was ist die EBNF?

A

Die Extended Backus-Naur Form (EBNF) ist eine formale Metasprache (also eine Sprache ΓΌber eine Sprache), die verwendet wird, um formale Grammatiken zu definieren. Man kann also ganze Programmiersprachen (z.B. C++) in EBNF umschreiben.

(Gutes Beispiel: https://de.wikipedia.org/wiki/Erweiterte_Backus-Naur-Form#Beispiel_Programmiersprache).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Was bedeutet Parsing und was ist ein Parser? Wozu braucht man das Parsing?

A

Parsing ist per Definition die Syntaxanalyse einer Sprache, um danach auf die Semantik schliessen zu kΓΆnnen.
(Bsp. in einer β€œmenschlichen” Sprache: Man wΓΌrde einen Satz in seine grammatikalischen Bestandteile zerlegen, was z.B. ein wichtiger Bestandteil der Linguistik ist.)
In C++ wird folglich mit dem Parsing festgestellt, ob ein Satz nach der EBNF gΓΌltig ist.
Dazu braucht man einen Parser, also das Programm zum Parsen.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Wie generiert man aus der EBNF einen Parser, um zu ΓΌberprΓΌfen, ob sein Satz in C++ gΓΌltig ist?

A

Man konvertiert EBNF-Elemente zu C++-Elementen:

  • Regeln werden zu Funktionen.
  • Alternativen und Optionen werden zu if-Anweisungen.
  • Nichtterminale Symbole auf der rechten Seite werden zu Funktionsaufrufen.
  • Optionale Repetitionen werden zu while-Anweisungen.

Beispiel:
Man definiert durch EBNF:

πšπšŠπšŒπšπš˜πš› = πšžπš—πšœπš’πšπš—πšŽπš_πš—πšžπš–πš‹πšŽπš› | β€œ(β€œ πšŽπš‘πš™πš›πšŽπšœπšœπš’πš˜πš— β€œ)” | β€œ-β€œ πšπšŠπšŒπšπš˜πš›.

πšπšŽπš›πš– = πšπšŠπšŒπšπš˜πš› { β€œ*” πšπšŠπšŒπšπš˜πš› | β€œ/” πšπšŠπšŒπšπš˜πš› }

πšŽπš‘πš™πš›πšŽπšœπšœπš’πš˜πš— = πšπšŽπš›πš– {β€œ+” πšπšŽπš›πš– | β€œ-β€œ πšπšŽπš›πš–}

Hier wurde β€œunsigned_number” schon vordefiniert. Weiterhin bedeuten β€œ|” Alternativen, geschweifte Klammern Wiederholungen, und in AnfΓΌhrungszeichen gestellte Symbole Terminalsymbole.
Es wird also z.B. ein Faktor definiert als eine natΓΌrliche Zahl ODER einen Ausdruck in Klammern ODER eine natΓΌrliche Zahl mit einem Minus vorne dran (was ja dann eine ganze Zahl wird).
In C++ wird dann eine Funktion definiert…
πš‹πš˜πš˜πš• πšπšŠπšŒπšπš˜πš› (𝚜𝚝𝚍::πš’πšœπšπš›πšŽπšŠπš–& πš’πš—_πšœπšπš›πšŽπšŠπš–);
… um zu ΓΌberprΓΌfen, ob es sich beim Eingabestrom tatsΓ€chlich um einen β€œFaktor” handelt, und falls ja, wird dieser extrahiert.

(FΓΌr genauere Angaben siehe PPT-Slides vom 12.11.2019)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly