FB Informatik Prof. Dr. R.Nitsch C++ - Kontrollstrukturen – Teil 2 Reiner Nitsch ℡ 8417 [email protected] Schleife und Verzweigung kombiniert FB Informatik Prof. Dr. R.Nitsch Wichtiger Baustein vieler Algorithmen! SV initialisieren while(B1) if(B2) w f V1 V2 Beispiel: Ägyptische Multiplikation für natürliche Zahlen ⎧ b ⎪⎪2ai 2 aib = ⎨ ⎪2aib + a ⎪⎩ 2 SV Richtung Ziel verändern falls b gerade falls b ungerade Ganzzahldivision! Erklärung: a = 20, b = 23 a • b = 2a • b/2 + a 20 • 23 = 40 • 11 + 1 • 20 40 • 11 = 80 • 5 + 1 • 40 80 • 5 = 160 • 2 + 1 • 80 160 • 2 = 320 • 1 + 0 • 160 320 • 1 = 640 • 0 + 1 • 320 Binärdarstellung von b 101112 = 2310 2010 • 101112 = 20 •(1 •24 + 0 •23 + 1 •22 + 1 •21 + 1 •20 ) = 320 + 0 •160 + 1 •80 + 1 •40 + 1 •20 = 460 → 20 • 23 = 460 17.05.2008 C++ Kontrollstrukturen - Teil 2 2 Ägyptische Multiplikation in C++ FB Informatik Prof. Dr. R.Nitsch int multiply( int a , int b ) { Produkt = 0 assert( a>0 && b>0 ); int product = 0; solange b > 0 while ( b > 0 ) { b ungerade? if ( b%2 == 1 ) // ist b ungerade ja nein product += a; Produkt um else a erhöhen ; a verdoppeln a *= 2; b /= 2; b halbieren } // while (b>0) return product; } Alternative Realisierung mit Bitmanipulationen • Test auf "b ungerade" durch Bittest → 101112 b = 2310 testmuster → 000012 = 110 b & testmuster → 00001 • Verdopplung: • Halbierung: a = 2010 = 000101002 b = 2310 = 000101112 2a = 4010 = 00101000 2 b/2 = 1110 = 00010112 0 17.05.2008 C++ Kontrollstrukturen - Teil 2 3 Ägyptische Multiplikation in C++ FB Informatik Prof. Dr. R.Nitsch int multiply( int a , int b ) { int product = 0; while ( b>0 ) { if ( b&1 ) // ist b ungerade product += a; else ; } // while (b>0) return product; } 17.05.2008 C++ Kontrollstrukturen - Teil 2 4 Rekursion FB Informatik Prof. Dr. R.Nitsch • Rekursive Funktionen – rufen sich wiederholt selbst auf – tun dies, um jeweils ein kleineres Problem zu lösen – enden erst dann ohne erneuten Selbstaufruf, wenn das Problem so klein ist, dass es gelöst werden kann (→ base case). Beispiel: Dreieckszahlen d0 = 0 d1 = 0 + 1 d2 = 0 + 1 + 2 d3 = 0 + 1 + 2 + 3 n n ( n + 1) k =0 2 dn = ∑ k = Iterative Lösung: d0 x d1 x x x d2 x x x x x x d3 x x x x x x x x x x d4 x x x x x x x x x x x x x x x d5 int triangleNumber ( int n ) { assert(n>=0); int result = 0; assert(result == n*(n+1)/2 ); return result ; } 17.05.2008 C++ Kontrollstrukturen - Teil 2 5 Rekursive Berechnung der Dreieckszahlen Rekursive Definition der Dreickzahlen: x x x x x dn = n + Rest = n + dn-1 x x x x x x x x x x FB Informatik Prof. Dr. R.Nitsch int triangleNumber( int n ) { assert( n>=0 ); d5 = 5 + Rest } 5 + d4 Aufruf in main: Rekursion wird durch das Konzept der lokalen cout << triangleNumber(3); Objekte ermöglicht: Jeder Aufruf erzeugt einen neuen Satz aller lokalen Objekte auf dem Stack! n Rückgabewert 1 9 3 3+3 = 6 2 8 2 2+1 = 3 3 7 1 0+1 = 1 4 6 0 5 17.05.2008 0 Rücksprungadresse n=3 Rückgabewert Rücksprungadresse n=2 Rückgabewert Rücksprungadresse n=1 Rückgabewert Rücksprungadresse n=0 Rückgabewert C++ Kontrollstrukturen - Teil 2 Vorsicht bei globalen Variablen in rekursiven Funktionen! 6 Rekursive Berechnung von n! Iterative Definition ⎧1 n! = ⎨ ⎩1⋅ 2 ⋅ ... ⋅ n für n = 0 für n>0 FB Informatik Prof. Dr. R.Nitsch // Rekursive Lösung long factorial ( int n ) { assert ( n>=0 ); Rekursive Definition 17.05.2008 C++ Kontrollstrukturen - Teil 2 7 Noch ein Beispiel FB Informatik Prof. Dr. R.Nitsch Invertieren einer beliebig langen Zeichenkette void reverseString () { char c; cin >> c; if ( c == '\n' ) return; else { reverseString (); cout << c; } } 17.05.2008 C++ Kontrollstrukturen - Teil 2 8 Rekursive Berechnung von Fibonacci-Zahlen Definition der Fibonacci Zahlen F(n) = 1 1 F(n-1) + F(n-2) für n = 0 für n = 1 für n > 1 Anwendung: Wachstumssimulation von Populationen Erklärung: Hasenpopulation h: Häschenpaar; 1 Monat Reifezeit H: Schwangere Häsin; 1 Monat Tragezeit) FB Informatik Prof. Dr. R.Nitsch Rekursive Realisierung in C++ long Fibonacci( int n ) { assert (n>=0); } Iterative Realisierung in C++ long Fibonacci ( int n ) { assert (n>=0); Monat Population long Fn, Fn_1(1), Fn_2(1); 0 h if (n<2) 1 H return 1; 2 Hh F(n-2) else 3 HHh F(n-1) while (n>1) { F(n) = F(n-1) + F(n-2) 4 HHHhh Fn = Fn_1 + Fn_2 5 HHHHHhhh Fn_2 = Fn_1; 6 HHHHHHhhhhh Fn_1 = Fn; n--; } return 1; 9 17.05.2008 C++ Kontrollstrukturen - Teil 2 } Türme von Hanoi - Problembeschreibung 17.05.2008 A B C Subturm Aufgabe: Turm aus 100 Scheiben umsetzen • 2 Ablagestellen • immer nur eine Scheibe transportieren • Es darf keine größere auf einer kleineren Scheibe liegen • Turm von A nach C unter Zuhilfenahme von B Algorithmischer Kern 1. Turm außer unterster Scheibe (Subturm) transportieren von A nach B (kleineres Problem) 2. unterste Scheibe transportieren von A nach B (base case) 3. Subturm von C nach B transportieren (kleineres Problem) FB Informatik Prof. Dr. R.Nitsch C++ Kontrollstrukturen - Teil 2 10 Türme von Hanoi - Implementation FB Informatik Prof. Dr. R.Nitsch void move( int amount, char from, char to, char hilfe ) { static int width(-5); //statische Variable mit Gültigkeitsbereich Programm width += 5; cout << endl; cout << string( width, ' ' ) << "Mein Auftrag ist: " << amount << " Scheibe(n) " << "von " << from << " nach " << to << endl; if ( amount == 1 ) // Base Case (realer Transport) cout << string( width, ' ' ) << "Ächz…Schwitz: " //Anwendung << " Scheibe Nr. " << amount void main(){ << "von " << from move( 3,'A','C','B' ); << " nach " << to << endl; cout << endl; else { // Unteraufträge (virtueller Transport) } // Subturm zur Hilfsposition move( amount-1, from, help, to ); //unterste Scheibe zur Zielposition 'nach' (realer Transport) cout << string( width,' ') << "Ächz…Schwitz: " << Scheibe Nr. " << amount << " von " << from << " nach " << to << endl; // Subturm von Hilfsposition 'Hilfe' zur Zielposition 'nach' move( amount-1, help, to, from ); width -=5; } //else } 17.05.2008 C++ Kontrollstrukturen - Teil 2 11 Türme von Hanoi - Ausgabe FB Informatik Prof. Dr. R.Nitsch A B C Mein Auftrag ist: 3 Scheibe(n) von A nach C Mein Auftrag ist: 2 Scheibe(n) von A nach B Mein Auftrag ist: 1 Scheibe(n) von A nach C Ich transportiere: 1 Scheibe(n) von A nach C Ich transportiere: 1 Scheibe von A nach B Mein Auftrag ist: 1 Scheibe(n) von C nach B Ich transportiere: 1 Scheibe(n) von C nach B Ich transportiere: 1 Scheibe von A nach C Mein Auftrag ist: 2 Scheibe(n) von B nach C Mein Auftrag ist: 1 Scheibe(n) von B nach A Ich transportiere: 1 Scheibe(n) von B nach A Ich transportiere: 1 Scheibe von B nach C Mein Auftrag ist: 1 Scheibe(n) von A nach C Ich transportiere: 1 Scheibe(n) von A nach C Press any key to continue 17.05.2008 C++ Kontrollstrukturen - Teil 2 12 Türme von Hanoi - Komplexität FB Informatik Prof. Dr. R.Nitsch Turm hat laut Überlieferung insgesamt n Scheiben 1. Mönch Scheibe n 1 mal transportieren 2. Mönch Scheibe n-1 2 mal transportieren 3. Mönch Scheibe n-2 4 mal transportieren 4. Mönch Scheibe n-3 8 mal transportieren i. Mönch Scheibe n+1-i 2i-1 mal transportieren n. Mönch Scheibe 1 2n-1 mal transportieren Summe: T = n ∑2 i −1 = 2n − 1 i =1 Weltuntergang, wenn alle 100 Scheiben transportiert sind? Annahme: Scheiben werden im Sekundentakt transportiert In wieviel Jahren ist dann der Weltuntergang? 17.05.2008 C++ Kontrollstrukturen - Teil 2 13