**Converting Recursion ↔ Iteration** CS Fundamentals · Stack Discipline --- # Part 1: Iteration → Recursion The simplest case. A `while` loop maps **directly** to tail recursion. The loop condition `C` becomes the base case (negated), and the loop body becomes the function body followed by a tail call. ~~~cpp // Iterative iter() { while ( C ) { code } } // Recursive equivalent rec() { if ( not C ) return; // base case = negated loop condition code // same body rec(); // tail recursion replaces the next iteration } ~~~ Because `rec()` is the **last** thing called, this is **tail recursion** — most compilers can optimize it back into a loop automatically. --- # Part 2: Recursion → Iteration (General Pattern) Recursive functions often **build up an object** as they go deeper, then act on it when the base case is reached. ~~~cpp rec( obj ) { if ( A complete ) { // base case update/print/use obj return } // else: extend and recurse rec( obj + next piece ) } ~~~ The key insight: **function frames on the call stack are just stored objects**. We can replace them with an explicit `std::stack`. ~~~cpp iter() { std::stack openlist; // stores unfinished work (was: call stack frames) openlist.push( {} ); // empty/initial object — was: first call while ( not openlist.empty() ) { A = openlist.pop(); // top + pop — was: entering a function call if ( A complete ) { // was: base case update/print/use obj continue } openlist.push( A + next piece ); // was: recursive call } } ~~~ > **Note:** There's an unfortunate play on words here — > the *call stack* (implicit, runtime) is replaced by a *stack data structure* > (explicit, yours to control). Same concept, different layer. --- # Example: Branch & Bound Assignment A concrete application: finding an optimal job assignment via branch and bound. ~~~cpp // Recursive — A is a partial assignment of jobs, e.g. J2 J1 J4 ... rec( A ) { if ( A complete ) { // base case: all jobs assigned update BST if better return } for each remaining job J { A += J calc LB of future assignments if ( g + LB < BSF ) { // prune: only recurse if promising rec( A ) } A -= J // backtrack } } ~~~ The recursive version implicitly relies on the **call stack** to remember which jobs are still being tried at each level. --- # Example: Branch & Bound — Iterative Version Replace the call stack with `std::stack openlist`. Structure is identical. ~~~cpp iter() { std::stack openlist; openlist.push( {} ); // start with empty assignment while ( not openlist.empty() ) { A = openlist.pop(); if ( A complete ) { // was: base case update BSF if better continue } // simulates the recursive calls + for-loop for each remaining job J { A += J calc LB of future assignments if ( g + LB < BSF ) { // same pruning condition openlist.push( A ); // was: rec( A ) } A -= J } } } ~~~ Every `rec(A)` call becomes `openlist.push(A)`. The `while` loop replaces the runtime's call scheduling. --- # Side-by-Side Summary | Recursive concept | Iterative equivalent | |---|---| | Function call `rec(obj)` | `openlist.push(obj)` | | Return / base case | `continue` (skip further work) | | Call stack (implicit) | `std::stack openlist` (explicit) | | Backtracking (`A -= J`) | Undo before pushing alternatives | | Pruning `if (...)` | Same `if (...)` before pushing | **The transformation is mechanical** — once you see that a call frame *is just an object on a stack*, the rest follows. ---