1 / 42

CS 163 Data Structures Chapter 7 C++ Simulation of Recursion

CS 163 Data Structures Chapter 7 C++ Simulation of Recursion. Herbert G. Mayer, PSU Status 6/8/2015. Syllabus. Definition of Recursive Algorithm Recursion vs. Iteration Fact() and Fibo (), Recursive and Iterative Q-Sequence Ackermann Function Stack Data Structure

mflaherty
Download Presentation

CS 163 Data Structures Chapter 7 C++ Simulation of Recursion

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS 163Data StructuresChapter 7C++ Simulation of Recursion Herbert G. Mayer, PSU Status 6/8/2015

  2. Syllabus • Definition of Recursive Algorithm • Recursion vs. Iteration • Fact() and Fibo(), Recursiveand Iterative • Q-Sequence • Ackermann Function • Stack Data Structure • Simulate Recursion via Iteration • References

  3. Definition of Recursive Algorithm • Recall: An algorithms is recursive, if partly defined by simpler versions of itself [1] • A recursive program is the implementation of a recursive algorithm • What is the problem for a programmer, using a language that is non-recursive (e.g. standard Fortran) if the algorithm to be implemented is recursive? --See later! • What then are the other parts of a recursive algorithm, aside from the partly? • Correct recursive algorithm requires a starting point, formally known as “base case” • Base case could be multiple steps • Simpler version means: the algorithm cannot use the original call. For example, if the original call was a(n), the recursive call cannot also be a(n), but perhaps a(n-1) • Recursive body can be indirectly recursive through intermediate function • a()-> b()-> a() – through intermediate function b() • Primitive examples are the factorial( n ) function; or Fibonacci( n ), for non-negative arguments n; Fibo( n ) shown here, discussed next: • Base case 1: Fibo(0) = 0 • Base case 2: Fibo(1) = 1 • Recursive Definition: Fibo( n ) for n > 1 = Fibo( n-1 ) + Fibo( n-2 )

  4. Recursion vs. Iteration • Iteration is expressed in programming languages by loops; e.g. for-, while-, do-, or repeat loops • These are readable and efficient methods for expressing iteration, but are not strictly necessary • Recursion can replace iterative steps; yet for some people this seems counter-intuitive • Neophytes are sometimes unused to recursion; yet recursion can be as intuitive as simple iteration 

  5. Fact() and Fibo(), Recursive + Iterative • We’ll show both solutions for the factorial and the fibonacci functions • Factorial: fact1() iterative, fact2() recursive • Fibonacci: fibo1() iterative, fibo2() recursive • Sometimes the recursive algorithm is easier to see + understand, if the problem is inherently recursive • Fibonacci was Italian mathematician in Pisa, 1170 – c. 1250; introduced Hindu-Arabic numeral system to Europe • Also show the famous Towers of Hanoi

  6. Fact() and Fibo(), Recursive + Iterative • Factorial( n ) is the product of the first n unsigned numbers, with factorial(0) defined as = 1 • Fibonacci( n ) is defined as 0 and 1 for arguments indexed 0, and 1. For all other n the result is the sum of the previous 2 Fibonacci numbers, i.e. Fibonacci( n ) = Fibonacci( n-1 ) + Fibonacci( n-2 ), for all n > 1

  7. Fact(), Recursive and Iterative • #include <iostream.h> • unsigned fact1( unsigned arg ) // iterative • { // fact1 • unsigned int result = 1; • for ( int i = 1; i <= arg; i++ ) { • result *= i; • } //end for • return result; • } //end fact1 • unsigned fact2( unsigned arg ) // recursive • { // fact2 • if ( arg < 2 ) { • return 1; • }else{ • return arg * fact2( arg-1 ); • } //end if • } //end fact2

  8. Fact(), Recursive and Iterative • int main( void ) • { // main • for ( int i = 0; i < 10; i++ ) { • cout << "fact1(" << i << ") = " << fact1( i ) << endl • << "fact2(" << i << ") = " << fact2( i ) << endl; • } //end for • return 0; • } //end main • fact1(0) = 1 • fact2(0) = 1 • fact1(1) = 1 • fact2(1) = 1 • fact1(2) = 2 • fact2(2) = 2 • . . . • fact1(7) = 5040 • fact2(7) = 5040 • fact1(8) = 40320 • fact2(8) = 40320 • fact1(9) = 362880 • fact2(9) = 362880

  9. Fibo(), Recursive and Iterative • #include <iostream.h> • unsigned fibo1( unsigned arg ) // iterative • { // fibo1 • unsigned fm2 = 0; • unsigned fm1 = 1; • unsigned fm0 = 1; • for ( int i = 1; i <= arg; i++ ) { • fm2 = fm1; • fm1 = fm0; • fm0 = fm1 + fm2; • } //end for • return fm2; • } //end fibo1 • unsigned fibo2( unsigned arg ) // recursive • { // fibo2 • if ( arg < 2 ) { • return arg; • }else{ • return fibo2( arg-1 ) + fibo2( arg-2 ); • } //end if • } //end fibo2

  10. Fibo(), Recursive and Iterative • int main( void ) • { // main • for ( int i = 0; i < 10; i++ ) { • cout << "fibo1(" << i << ") = " << fibo1( i ) << endl • << "fibo2(" << i << ") = " << fibo2( i ) << endl; • } //end for • return 0; • } //end main • fibo1(0) = 0 • fibo2(0) = 0 • fibo1(1) = 1 • fibo2(1) = 1 • fibo1(2) = 1 • fibo2(2) = 1 • fibo1(3) = 2 • fibo2(3) = 2 • fibo1(4) = 3 • fibo2(4) = 3 • . . . • fibo1(9) = 34 • fibo2(9) = 34

  11. Replace Iteration via Recursion • What is the problem, if algorithm to be programmed is recursive, but language does not allow recursion? • Rewrite the algorithm • Or simulate recursion • Here we do the opposite: Use recursion to simulate all mathematical dyadic operations + - / * etc. • Using only functions, called recursively • Plus arithmetic increment/decrement operators ++ --and unary minus – • And conventional relational operators > >= != etc. • All other operators are dis-allowed, i.e. cannot use + - * / % **etc.

  12. Recursion vs. Iteration: add() // return a +b without + operation! int add( int a, int b ) { // add if ( 0 == b ) { return a; }else if ( b < 0 ) { return add( --a, ++b ); }else{ return add( ++a, --b ); } //end if } //end add

  13. Recursion vs. Iteration: sub() // return a – b; no dyadic – operation int sub( int a, int b ) { // sub return add( a, -b ); } //end sub

  14. Recursion vs. Iteration: mult() • // return a * b, no * but add(), mult() ... • int mult( int a, int b ) • { // mult • if ( 0 == b ) { • return 0; • }else if ( 1 == b ) { • return a; • }else if ( b < 0 ) { • return -mult( a, -b ); • }else{ • // b > 0 • return add( a, mult( a, --b ) ); • } //end if • } //end mult

  15. Recursion vs. Iteration: expo() // return a ** b, no ** op in C++; requires mult( int, int ) int expo( int a, int b ) { // expo if ( 0 == a ) { if ( 0 == b ) { printf( ”undefined value0^0\n" ); }else if ( b < 0 ) { printf( “0 to <0 power is undefined\n" ); } //end if return 0; }else if ( 0 == b ) { return 1; }else if ( 1 == a ) { return 1; }else if ( -1 == a ) { return b % 2 ? -1 : 1; }else if ( b < 0 ) { return 0; }else{ return mult( expo( a, --b ), a ); } //end if } //end expo

  16. Q-Sequence, Definition Q-Sequence defined by Douglas Hofstadter in [1] as a function q( n ) for positive integers n > 0 Base case n = 1: q(1) = 1 Base case n = 2: q(2) = 1 Recursive definition of q(n), for positive n > 2 q( n ) = q( n – q( n - 1 ) ) + q( n – q( n - 2 ) ) Q-Sequence reminds us of Fibonacci( n ) function, but with surprising difference in the type of result: By contract, the function results of fibonacci( n )are monotonically increasing with increasing argument Results of q( n )are non-monotonic! Note # of calls: calls(q( 40 )) = 1,137,454,741

  17. Q-Sequence, Coded in C++ • #define MAX 100 // arbitrary limit; never reached!!!! • int calls; // will be initialized each time • int q( int arg ) • { // q • calls++; // track another call • if ( arg <= 2 ) { • return 1; // base case • }else{ // now recurse! • return q( arg - q( arg-1 ) ) + q( arg - q( arg-2 ) ); • } // end if • } // end q • void main() • { // main • for( int i = 1; i < MAX; i++ ) { • calls = 0; // initially no calls yet • printf( "Q(%2d) = %3d, #calls = %10d\n", i, q(i), calls ); • } // end for • } // end main

  18. Q-Sequence Results Q( 1) = 1, #calls = 1Q( 2) = 1, #calls = 1Q( 3) = 2, #calls = 5Q( 4) = 3, #calls = 13Q( 5) = 3, #calls = 25Q( 6) = 4, #calls = 49Q( 7) = 5, #calls = 93Q( 8) = 5, #calls = 161Q( 9) = 6, #calls = 281Q(10) = 6, #calls = 481Q(11) = 6, #calls = 813 . . . Q(26) = 14, #calls = 1341433Q(27) = 16, #calls = 2174493Q(28) = 16, #calls = 3521137Q(29) = 16, #calls = 5700281Q(30) = 16, #calls = 9229053Q(31) = 20, #calls = 14941993Q(32) = 17, #calls = 24182797Q(33) = 17, #calls = 39137473Q(34) = 20, #calls = 63354153Q(35) = 21, #calls = 102525697Q(36) = 19, #calls = 165896537Q(37) = 20, #calls = 268460333Q(38) = 22, #calls = 434429737Q(39) = 21, #calls = 702952137Q(40) = 22, #calls = 1137454741 . . . Will never reach Q(100) in your life time 

  19. Ackermann Definition Ackermann a( m, n ) is defined as a function of two non-negative (i.e. unsigned in C++) integers m and n Base case 1: a( 0, n ) = n + 1 Base case 2: a( m, 0 ) = a( m - 1, 1 ) Recursive definition of a( m, n ), m, n > 0 a( m, n ) = a( m - 1, a( m, n - 1 ) ) Ackermann complexity grows awfully fast; e.g. a(4,2) is an integer number with 19,729 decimal digits; greater than the national US debt!

  20. Ackermann Definition Students, code now in C++, volunteers shows result on white-board: Base case 1: a( 0, n ) = n + 1 Base case 2: a( m, 0 ) = a( m - 1, 1 ) Recursive definition of a( m, n ), m, n > 0 a( m, n ) = a( m - 1, a( m, n - 1 ) )

  21. Ackermann Coded in C++ unsigned a( unsigned m, unsigned n ) { // a calls++; // global unsigned if ( 0 == m ) { // note operand order return n + 1; // first base case }else if ( 0 == n ) { // m > 0 return a( m - 1, 1 ); // other base case }else{ // m > 0, n > 0 return a( m-1, a( m, n-1 ) ); // recurse! } // end if } // end q void main() { // main for( inti = 0; i < MAX; i++ ) { printf( "\nFor m = %d\n", i ); for( int j = 0; j < MAX; j++ ) { calls = 0; printf( "a(%1d,%1d) = %10u, calls = %12u\n", i, j, a( i, j ), calls ); } // end for } // end for return 0; } // end main

  22. Ackermann Results For m = 0a(0,0) = 1, calls = 1. . . For m = 1. . . a(1,7) = 9, calls = 16For m = 2a(2,0) = 3, calls = 5a(2,1) = 5, calls = 14a(2,2) = 7, calls = 27a(2,3) = 9, calls = 44a(2,4) = 11, calls = 65a(2,5) = 13, calls = 90a(2,6) = 15, calls = 119a(2,7) = 17, calls = 152For m = 3a(3,0) = 5, calls = 15a(3,1) = 13, calls = 106a(3,2) = 29, calls = 541a(3,3) = 61, calls = 2432a(3,4) = 125, calls = 10307a(3,5) = 253, calls = 42438a(3,6) = 509, calls = 172233a(3,7) = 1021, calls = 693964For m = 4a(4,0) = 13, calls = 107 don’t even dream about computing a(4,2)  or higher!

  23. Run Time Stack

  24. Stack Data Structure • High-level language functions call each other in a nested fashion, recursively, even indirectly recursively • And return in strictly the reverse order (LIFO), but with any number of further calls in between • Stack is the natural data structure to track caller and callée return information • Most programming languages allow local data in functions, of which formal parameters are just one variation • Natural to have locals also live and die on the run time stack, synchronized with call-return information

  25. Caller pushes formals bp Field 1: Function return value Field 2: return address Stack Marker Field 3: dynamic link Field 4: static link sp 0..32 registers saved Stack Frame 0 or more locals Other temps Stack Frame of callee hp Stack grows downwards Stack grows downward

  26. Stack Data Structure • Stack is natural data structure for recursive call: • 1.) Before call: provide (push) all actual parameters • During the call, these are the formal parameters • 2.) Then execute call, provide the return address on stack • Provide space on stack for return value if needed (function) • And push bp register, pointing to the frame of caller: known as dynamic link • 3.) Before executing callée code: allocate locals on stack • And allocate temps, e.g. copies of all regs to be used, save them and later restore before return • Thus stack grows by 3 physical + logical sections: • Actual = formal parameters, some of them just addresses • Stack Marker, AKA Activation Record: RA, RV, Dynamic Link • Locals + temps + saved registers

  27. Stack Data Structure • Stack is addressed by 2 hardware (HW) resources, typically registers bp and sp (AKA top, or stack pointer) • It is computable to have a single register address stack via current frame, since the compiler “knows” at each place, by how much stack must have grown • Actually so done by Greenhills compilers in 1990s for register-starved Intel architecture • Base Pointer register bp points to some defined place of stack marker, typically to the dynamic link • The top of stack register sp points to the dynamically changing, momentary top of stack –dynamic during the call • The bp stays invariant during the call; changes only at further calls and at any returns –static during the call • The sp changes with each call preparation, each temp pushed on top, each intermediate result, etc.

  28. Simulate Recursion via Iteration • Important for master programmer to understand RT-stack and recursion! • What to do, if you implement a recursive algorithm using a language that does not support recursion? • Replace recursive by a non-recursive algorithm! • Or simulate recursion via non-recursive methods • After all, a computer chip has no notion of recursion; it is a sequential machine that “simulates recursion” via non-recursive methods; the compiler plus run-time system perform this transformation! • Done so at local industry in the past: FPS used Fortran!! to implement System SW and compilers • Here are the actual steps of simulating recursion via iteration; must use language with Goto –terrible sin 

  29. Steps of Simulating Recursion • consider directly-recursive calls of simulated function: • Define data structure struct stack_tp, to hold params, locals, etc. • Define explicit stack with top of stack (top) index, initially top=0; like a real stack identified by sp, may overflow, so include code to check; stack[ top ] holds parameters, function return value, return location (labels after a recursive call), and automatics • Define labels for each point of recursive call, more precisely at each point after the call; number these points of return, e.g. l1, l2, l3, l4 etc. There shall be branches = gotos to these points of return • At each point ofrecursive call: • Increment : i.e. top++, like HW recursion that grows and shrinks sp • Manually move parameters for “this call” onto stack; e.g. assign: stack[ top ].arg1 = actual1; stack[ top ].arg2 = actual2 . . . • Store the place of return: stack[ top ].ret = 1, or 2, or 3 alluding to l1, l2, l3 . . . • Initialize local, automatic objects: stack[ top ].local1 = value1 . . . • Jump to the function head, not including initializing code

  30. Steps of Simulating Recursion • 5. Point of return --best to centralize one single point of return: • Decrement the top of stack: top-- • Check, to which of the stored labels the flow of control has to branch to simulate a return; e.g.: if ( stack[ top+1 ].ret == xyz ) goto label_xyz; • And if no other branch is open, then fall through to the end • For void functions this is a literal fall-through • For true functions, the return value has to be computed before the fall-through, e.g.: return stack[ top ].return_value; • 6. For nested recursive calls or several recursive calls in a row or both: “be creative” ; see an example later; apply these steps with meticulous precision

  31. Simulate Recursion, fact() • #include <stdio.h> • #define MAX_STACK 100 // never reached or exceeded! • #define MAX 14 // higher factorial overflows 32bits • unsigned calls = 0; // track # of calls • typedef struct s_tp { • unsigned arg; // for formal parameters • unsigned fact; // function return value • unsigned ret; // code address after call, return! • } struct_s_tp; • // first the recursive fact() function for reference • // includes tracking # of calls • unsigned fact( unsigned arg ) • { // fact • calls++; // gotta be global • if ( 0 == arg ) { // why strange order? • return 1; • }else{ • return fact( arg - 1 ) * arg; • } // end if • // there should be an assertion here! • } // end fact

  32. Simulate Recursion, fact() • unsigned nrfact( unsigned arg ) • { // nrfact • struct_s_tp s[ MAX_STACK ]; // simulate RT stack s[]! • unsigned top = 0; // simulate sp register • s[ top ].arg = arg; // this call’s argument • s[ top ].ret = 3; // 3 alludes to label l3 • l1: if ( 0 == s[ top ].arg ) { • s[ top ].fact = 1; • }else{ • top++; // recursion! • s[ top ].arg = s[ top-1 ].arg-1; • s[ top ].ret = 2; // remember label l2 • goto l1; // now simulate recursion • l2: • // back from recursive call • top--; // sp-- • s[ top ].fact = s[ top + 1 ].fact * s[ top ].arg; • } // end if • if ( s[ top ].ret == 2 ) { // test, where to branch to • goto l2; // unstructured goto into if • } // end if • l3: • return s[ top ].fact; • } // end nrfact

  33. Simulate Recursion, fact() Result r_fact( 0) = 1, calls = 1 r_fact( 1) = 1, calls = 2 r_fact( 2) = 2, calls = 3 r_fact( 3) = 6, calls = 4 r_fact( 4) = 24, calls = 5 r_fact( 5) = 120, calls = 6 r_fact( 6) = 720, calls = 7 r_fact( 7) = 5040, calls = 8 r_fact( 8) = 40320, calls = 9 r_fact( 9) = 362880, calls = 10 r_fact(10) = 3628800, calls = 11 r_fact(11) = 39916800, calls = 12 r_fact(12) = 479001600, calls = 13 r_fact(13) = 1932053504, calls = 14nr_fact( 0) = 1nr_fact( 1) = 1nr_fact( 2) = 2nr_fact( 3) = 6nr_fact( 4) = 24nr_fact( 5) = 120nr_fact( 6) = 720nr_fact( 7) = 5040nr_fact( 8) = 40320nr_fact( 9) = 362880nr_fact(10) = 3628800nr_fact(11) = 39916800nr_fact(12) = 479001600nr_fact(13) = 1932053504

  34. Simulate Recursion, fibo() #define MAX_STACK 100 // never to be reached or exceeded! #define MAX 30 // higher fibo(n) not computable! unsigned calls; // in case we track # of calls typedef struct s_tp { // type of stack unsigned arg; // copy of fibo’sarg unsigned fibo; // return value for fibo unsigned ret; // to which label to goto? } struct_s_tp; // recursive function for reference: unsigned fibo( unsigned arg ) { // fibo calls++; if ( arg <= 1 ) { // base case? return arg; // if so: done! }else{ return fibo( arg-1 ) + fibo( arg-2 ); } // end if } // end fibo

  35. Simulate Recursion, fibo() unsigned nr_fibo( unsigned arg ) { //nr_fibo struct_s_tp s[ MAX_STACK ]; // stack can be local unsigned top = 0; // initially s[ top ].arg = arg; // copy arg to stack s[ top ].ret = 4; // if all fails, return l1: if ( s[ top ].arg <= 1 ) { s[ top ].fibo = s[ top ].arg; }else{ top++; // ready to recurse s[ top ].arg = s[ top - 1 ].arg - 1; s[ top ].ret = 2; // to place of 1. return goto l1; // recurse! l2: top++; // ready to recurse again s[ top ].arg = s[ top - 2 ].arg - 2; s[ top ].ret = 3; // to place of 2nd return goto l1; // recurse! l3: // two returns simulated top -= 2; // simulate 2 returns s[ top ].fibo = s[ top + 1 ].fibo + s[ top + 2 ].fibo; } // end if if ( 2 == s[ top ].ret ) { // second recursive call goto l2; }else if ( 3 == s[ top ].ret ) { gotol3; } // end if l4: return s[ top ].fibo; // all done } // end nr_fibo

  36. Simulate Recursion, fibo()Result r_fibo( 0) = 0, calls = 1r_fibo( 1) = 1, calls = 1r_fibo( 2) = 1, calls = 3 r_fibo( 3) = 2, calls = 5r_fibo( 4) = 3, calls = 9 . . . r_fibo(22) = 17711, calls = 57313r_fibo(23) = 28657, calls = 92735r_fibo(24) = 46368, calls = 150049r_fibo(25) = 75025, calls = 242785r_fibo(26) = 121393, calls = 392835r_fibo(27) = 196418, calls = 635621r_fibo(28) = 317811, calls = 1028457r_fibo(29) = 514229, calls = 1664079nr_fibo( 0) = 0nr_fibo( 1) = 1nr_fibo( 2) = 1nr_fibo( 3) = 2nr_fibo( 4) = 3 . . . nr_fibo(22) = 17711nr_fibo(23) = 28657nr_fibo(24) = 46368nr_fibo(25) = 75025nr_fibo(26) = 121393nr_fibo(27) = 196418nr_fibo(28) = 317811nr_fibo(29) = 514229

  37. Simulating Return of fibo() • Must the computation of the continuation place be after the if-statement? Or can we relocate it into the Else-Clause? • That would lead to a partial simulation, in which only the case arg > 1 continues correctly • Yet even cases for arg <= 1 must compute the right continuation via brute-force gotos: • if ( 2 == s[ top ].ret ) { // second recursive call • goto l2; • }else if ( 3 == s[ top ].ret ) { • goto l3; // to return place • } // end if

  38. Towers of hanoi() • The game of the “Towers of Hanoi” is a game to move a stack of n discs, while obeying certain rules • All n discs are of different sizes, residing on top of one another, a smaller disc always over a larger • The goal is to move the whole tower from start, to the goal position, using one additional buffer location • But only moving 1 single disc at a time • And never placing a larger disc on top of a smaller • During various times, any disc may be placed on the start position, the goal, or the buffer

  39. Towers of hanoi(), Recursive #include <iostream.h> #define MAX … some small integer < 32 void hanoi( int discs, char* start, char* goal, char* buff ) { // hanoi if ( discs > 0 ){ hanoi( discs-1, start, buff, goal ); cout << "move disc " << discs << " from " << start << " to “ << goal << endl; hanoi( discs-1, buff, goal, start ); } // end if } // end hanoi intmain() { // main for ( int discs = 1; discs <= MAX; discs++ ) { cout << ” hanoifor " << discs << " discs" << endl; hanoi( discs, "start", "goal ", "buff " ); cout << endl; } // end for return 0; } // end main

  40. Towers of hanoi(), Recursive move disc 1 from start to goal < For 1 disc move disc 1 from start to buff < For 2 discs move disc 2 from start to goal move disc 1 from buff to goal move disc 1 from start to goal < For 3 discs move disc 2 from start to buff move disc 1 from goal to buff move disc 3 from start to goal move disc 1 from buff to start move disc 2 from buff to goal move disc 1 from start to goal move disc 1 from start to buff < For 4 discs move disc 2 from start to goal move disc 1 from buff to goal move disc 3 from start to buff move disc 1 from goal to start move disc 2 from goal to buff move disc 1 from start to buff move disc 4 from start to goal move disc 1 from buff to goal move disc 2 from buff to start move disc 1 from goal to start move disc 3 from buff to goal move disc 1 from start to buff move disc 2 from start to goal move disc 1 from buff to goal

  41. Simulate Recursion, hanoi() void nr_hanoi( unsigned discs, char* start, char* goal, char* buff ) { // nr_hanoi struct_h_type s[ MAX_STACK ]; unsigned top = 0; s[ top ].discs = discs; s[ top ].start = start; s[ top ].buff = buff; s[ top ].goal = goal; s[ top ].ret = 4; l1: if ( s[ top ].discs > 0 ) { top++; s[ top ].discs = s[ top-1 ].discs - 1; s[ top ].start = s[ top-1 ].start; s[ top ].buff = s[ top-1 ].goal; s[ top ].goal = s[ top-1 ].buff; s[ top ].ret = 2; goto l1; l2: cout << "nr move disc “ << s[ top ].discs << “ from “ << s[ top ].start << “ to “ << s[ top ].goal << endl; top++; s[ top ].discs = s[ top-1 ].discs - 1; s[ top ].start = s[ top-1 ].buff; s[ top ].buff = s[ top-1 ].start; s[ top ].goal = s[ top-1 ].goal; s[ top ].ret = 3; goto l1; } // end if l3: if ( 2 == s[ top ].ret ) { top--; goto l2; }else if ( 3 == s[ top ].ret ) { top--; goto l3; } // end if } // end nr_hanoi

  42. References • Douglas R. Hofstadter, “Gödel, Escher, Bach: an eternal golden braid”, Basic Books, 1999, ISBN 0465026567; came out in 1979 • Ackermann function at NIST: http://xlinux.nist.gov/dads/HTML/ackermann.html • Herbert G Mayer: “Advanced C Programming on the IBM PC”, 1989, Windcrest, ISBN 0-8306-9163-4 • Non-recursive solution to Towers of Hanoi: http://portal.acm.org/citation.cfm?id=948602 • Herbert G Mayer, Don Perkins, SIGLAN Notices, 1984, non-recursive Towers of Hanoi Solution: http://dl.acm.org/citation.cfm?id=948573

More Related