8F. Nested Loops and Nested Loop Emulation


Nested loops

Loops are nested when one loop is inside another. For example, if nestdemo is defined by

  void nestdemo()
  {
    printf("  i  j\n");
    int i = 1;
    while(i <= 4)
    {
      int j = 1;
      while(j <= 4)
      {
         printf("%3i%3i\n", i, j);
         j++;
      }
      i++;
    }
  }

then nestdemo() prints

  i  j
  1  1
  1  2
  1  3
  1  4
  2  1
  2  2
  2  3
  2  4
  3  1
  3  2
  3  3
  3  4
  4  1
  4  2
  4  3
  4  4

The coding standards for this course require each function to contain no more than one loop. As a consequence, you cannot directly write nested loops. What should you do? Pull the inner loop out into a separate function.

  void dorow(int i)
  {
    int j = 1;
    while(j <= 4)
    {
       printf("%3i%3i\n", i, j);
       j++;
    }
  }

  void nestdemo()
  {
    int i = 1;
    while(i <= 4)
    {
      dorow(i);
      i++;
    }
  }  

Nested loop emulation

Upon seeing that the standards disallow directly nested loops, some students try using nested loop emulation, which uses one loop to emulate two nested loops. Typically, there are two control variables (say, i and j) that are managed in the loop body so that the values of i and j change in a way that is like the nestdemo example above. Here is conversion of the above nested loops into a single emulating loop.

  int i = 1;
  int j = 1;
  while(i <= 4)
  {
    printf("%3i%3i\n", i, j);
    j++;
    if(j == 5)
    {
      j = 1;
      i++;
    }
  }

Notice that, when j = 5, the loop body moves to the next value of i and restarts the loop on j. That is not an improvement. It is much more difficult to understand than the original two nested loops, and it is not an acceptable thing to do. The standards disallow nested loop emulation like that.

To deal with nested loops, pull the inner loop out into a separate function, as shown above.


Exercises

  1. What is nested-loop emulation, and why shouldn't you use it? Answer

  2. Rewrite the following by pulling the inner loop out into a separate function.

      // countOrderedPairs(n) returns a count of the number of
      // ordered pairs (i,j) where 1 <= i,j <= n and i > j.
      // For example, the ordered pairs containing integers from
      // 1 to 3 are: (1,1), (1,2), (1,3), (2,1), (2,2), (2,3),
      // (3,1), (3,2), (3,3).  In 3 of those ordered pairs, the first
      // number is larger than the second number.  So countOrderedPairs(3)
      // returns 3.
    
      int countOrderedPairs(int n)
      {
        int i, j, count = 0;
    
        i = 1;
        while(i <= n)
        {
          j = 1;
          while(j <= n)
          {
            if(i > j)
            {
              count++;
            }
            j++;
          }
          i++;
        }
        return count;
      }
    

    Hint. The function that performs the inner loop will need to know the value of i as well as the value of n. It can return the number of ordered pairs of the form (i, j) where i > j and 1 ≤ jn.

    Note. For this problem, it is easy to avoid the inner loop altogether since, for a given i, the number of ordered pairs (i, j) where i > j and 1 ≤ jn is just i − 1. But, since this is an exercise in pulling an inner loop out, don't make that improvement. Keep the algorithm the same.

    Answer