14B. Recursive Scan Algorithms

We have seen how to write scan algorithms using loops. Anything you can do with a loop, you can also do with recursion. The preceding page included a definition of sum(A, n). Here are some additional examples.


Largest

Let's define function largest(A, n), which returns the largest value among the first n values in array A, where n > 0.

Be sure to remember that the first n variables in array A are A[0], … A[n−1].

If n = 1, there is only one value, A[0], to consider. That one must be the largest.

If n > 1, compute m = largest(A, n−1), the largest of the first n−1 values in A. Then the largest of the first n values in A must either be m or A[n-1], whichever one is larger.

Here is a definition of largest(A, n) that uses those ideas.

  // largest(A,n) returns the largest of A[0],...,A[n-1].
  //
  // It is required that n > 0.

  int largest(const int A[], const int n)
  {
    if(n == 1)
    {
      return A[0];
    }
    else
    {
      int m = largest(A, n-1);
      return max(m, A[n-1]);
    }
  }

SumPrimes

Here is an implementation of sumPrimes(n), which returns the sume of the prime numbers that are less than or equal to n. We implemented sumPrimes previously using a loop. Because of the filtering (considering only at prime numbers), there is one more case than in sum or largest.

Since the smallest prime number is 2, sumPrimes(n) = 0 when n < 2. Otherwise, compute m = sumPrimes(n−1). If n is not prime, then sumPrimes(n) = m. If n is prime, sumPrimes(n) = m + n.

  //==============================================
  // sumPrimes(n) yields the sum of the prime
  // numbers that are less than or equal to n.
  // For example, sumPrimes(5) = 2 + 3 + 5 = 10.
  //==============================================

  int sumPrimes(const int n)
  {
    if(n < 2)
    {
      return 0;
    }
    else 
    {
      const int m = sumPrimes(n-1);
      if(isPrime(n))
      {
        return m + n;
      }
      else
      {
        return m;
      }
    }
  }

ConvertToInt

This example uses arrays of characters, called null-terminated strings. If you understand arrays, you should be able to understand this example.

ConvertToInt(s), previously implemented with a loop, introduces a new issue. Using only what we know now about arrays, it is not possible to write convertToInt directly. We need a helper function with two parameters. Later, when we look at arrays in more detail, we will see how to write convertToInt directly using recursion.

Library function strlen(s) returns the length of null-terminated string s. For example, strlen("abc") yields 3. Include <cstring> to use strlen. (Note: Earlier, we said that you cannot ask an array how large it is. But strlen(s) does not really tell how large array s is. It tells the index of the first null character in s, and that is easy to do with a loop.)

  //===============================================
  // convertToInt2(s, n) yields the result of
  // converting the first n characters of s to an
  // integer. s must be a null-terminated string.
  //
  // For example, 
  //   convertToInt2("12345", 5) returns 12345,
  //   convertToInt2("12345", 4) returns 1234,
  //   convertToInt2("12345", 3) returns 123,
  //   convertToInt2("12345", 2) returns 12,
  //   convertToInt2("12345", 1) returns 1,
  //   convertToInt2("12345", 0) returns 0.
  //
  // Requirement: s must be a null-terminated string
  // that only contains decimal digits.
  //===============================================

  int convertToInt2(const char s[], const int n)
  {
    if(n == 0)
    {
      return 0;
    }
    else 
    {
      int lastDigit = s[n-1] - '0';
      return 10*convertToInt(s, n-1) + lastDigit;
    }
  }

  //===============================================
  // convertToInt(s) yields the integer described
  // by string s. For example, convertToInt("325")
  // = 325.
  //
  // Requirement: s must be a null-terminated string
  // that only contains decimal digits.
  //===============================================

  int convertToInt(const char s[])
  {
    return convertToInt2(s, strlen(s));
  }

Let's do a hand simulation of convertToInt("51449") using the rule that recursive calls are assumed to work correctly.

convertToInt("61449") = convertToInt2("61449", 5)
= 10*convertToInt2("6144", 4) + 9
= 10*6144 + 9  according to the contract for convertToInt2
= 61449

The simulation shows that convertToInt("61449") = 61449, which is the correct answer.


Exercises

  1. Using recursion, write a definition of sumsq(n), which returns 12 + 22 + … n2. Answer

  2. Write a recursive definition of function numPrimes(n), which returns a count of how many of 1, …, n are prime. Answer