Lecture 23 - Oct 23, 2023

Summary

In this lecture, we introduce recursion, and we discuss how to think recursively.

Last lecture

Midterm revision.

Today

Recursion.

Recursion

Recursion is a programming technique that involves solving a problem by breaking it into a smaller problem repeatedly until it is small enough to be solved easily. Solutions of smaller problems can then be combined to form the solution of the original bigger problem.

Example

Write a function that gets the factorial of n recursively.

\[\begin{eqnarray*} n! &= n \times (n - 1) \times (n - 2) \times \cdots \times 3 \times 2 \times 1 \\ n! &= n \times (n - 1)! \\ 4! &= 4 \times 3! = 3 \times 2! = 2 \times 1! = 2 \end{eqnarray*}\]

  1. Recursively get the factorial of a smaller number.
  2. Repeat until we reach the terminating case.
  3. Combine the solutions to get the bigger problem’s solutions.
int factorial(int n) {
  if (n == 1 || n == 0) {
    return 1; // base case
  } else {
    return n * factorial(n - 1); // recursive case
  }
}

int main() {
  int f = factorial(3); // f = 6
  return 0;
}

The call to factorial(3) would create recursive function calls.

int factorial(int 3) {
  if (3 == 1 || 3 == 0) {
    return 1; // base case
  } else {
    return 3 * factorial(3 - 1); // recursive case
  }
}

  int factorial(int 2) {
    if (2 == 1 || 2 == 0) {
      return 1; // base case
    } else {
      return 2 * factorial(2 - 1); // recursive case
    }
  }

    int factorial(int 1) {
      if (1 == 1 || 1 == 0) {
        return 1; // base case
      } else {
        return 1 * factorial(1 - 1); // recursive case
      }
    }

diagrams/lecture26-diagram1.svg

Example

Given an array of n integers, sum the elements of the array.

sumOfArray(0->4) = array[0] + sumOfArray(1->4)
sumOfArray(1->4) = array[1] + sumOfArray(2->4)
...
int sumOfArray(int a[], int left, int right) {
  if (left == right) {
    return a[left];
  } else {
    return a[left] + sumOfArray(a, left + 1, right);
  }
}

We need to communicate to the next recursive function call from where should we
start adding and until where (e.g. `left` and `right`).
:::

::: {.callout-note icon=false}
## Example

Print nodes in a linked list recursively.

<img src="diagrams/lecture18-diagram1.svg" alt="diagrams/lecture18-diagram1.svg">

```cpp
class Node {
  public:
    int data;
    Node* head;
};

void rprint(Node* p) {
  if (p == NULL) {
    return; // base case
  } else {
    cout << p->data;
    rprint(p->next); // recursive case
  }
}

int main() {
  List L;
  ...

  rprint(L->getHead()); // L->getHead() = Node*
  ...
  
}