CS 261 University of Puget Sound Spring, 2020
 
Computer Science II
Abstract Data Types and their Implementations, Some Basic Algorithms,
Object-oriented Problem Solving, and Efficiency
 

Warning: This course is under development. Although the basic structure of this course is largely established, nothing on this Web site should be considered official or even possibly correct.
DO NOT MAKE PLANS BASED ON THE CONTENTS OF THIS SITE UNTIL JANUARY, 2020.

Recursion: The Basics

Goals

This lab provides practice using recursion—first with numbers (expanding work done earlier) and then with lists (using the structure of lists to motivate recursive algorithms).

Steps for this Lab

Practice with numbers

The first 3 steps of this lab involve using recursion in numeric computations—first reviewing an example and then writing some code.

  1. Consider the following recursive method power:

    /* compute the base raised to the exponent
       @param base:  the number being raised to a power
       @param exponent:  the power 
       @pre-condition:  exponent is non-negative
    */
    public static int power (int base, int exponent) {
       if (exponent <= 1) {
           return base;
       } else {
           return  base * power(base, (exponent - 1))
       }
    }
    
    1. Run power on several test cases that illustrate that this procedure performs as indicated by the pre- and post-conditions.

    2. Write a paragraph to explain how power accomplishes its task.

  2. Write a recursive static method public countdown (int n) that takes a non-negative integer as parameter and prints lines that count down to 0, such as the following for the call countdown (5):

        5
        4
        3
        2
        1
        Hurray!
      
  3. Write a recursive static method public int termial (int n) that computes the termial of any natural number number, that is, the result of adding together all of the natural numbers up to and including number. Here are some illustrative sample calls:

      termial (7)   ===> 28 // = 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
      termial (1)   ===> 1  // = 1 + 0
      termial (0)   ===> 0
    
  4. Write a recursive method public static int factorial (int n) that takes a non-negative integer as parameter and returns n factorial (that is n*(n-1)*(n-2)*.. . * 3*2*1 ).

Recursion with Lists

Lists can be defined in several ways. A particularly common and useful approach for a list of type E items is recursive:

Notice that this definition refers to itself (for a simpler list), so the definition is recursive. In practice, this list definition indicates that lists can be constructed from a null list by successively adding items at the front.

This type of definition leads naturally to many recursive algorithms, in which we process the first element and combine it with the processing of the rest.

For the next exercises, suppose a StringNode with string data is defined as follows:

  public class IntNode {
     protected int data;
     protected IntNode next;

     public IntNode (int item, next) {
        data = item;
        this.next = next;
     }
     /* getters and/or setters follow */

Constructing Lists of integers

  1. Consider the following procedure public IntNode decendingList (int start) that takes any non-negative integer start as its argument returns a list of all the positive integers less than or equal to start, in descending order:

    descendingList (5) ===> (5 4 3 2 1)
    descendingList (1) ===> (1)
    descendingList (0) ===> ()
    

    Appropriate code follows:

      public IntNode descendingList (int start) {
         if (start == 0) {
             return null;
         } else {             
             return new IntNode (start, descendingList (start-1));     
         }
      }
    
    1. Explain (in English) what this procedure does and how.
    2. Test descendingList with several beginning values and observe what happens.
    3. Suppose the initial parameter is negative? What happens, and how could the code be modified to resolve that situation.
  2. Write a method public IntNode listOfZeros (int n) that takes a non-negative integer as parameter and returns a list of n zeros:

    listOfZeros (5) ===> (0 0 0 0 0)
    listOfZeros (1) ===> (0)
    listOfZeros (0) ===> ()
      

Processing Lists of Integers

  1. Consider the following methods that process data in an IntNode.

    For each of these methods, answer the following:

    1. Correcting any syntax errors that might arise, and run each method on several test cases to clarify what results are obtained.
    2. Explain (in English) what this procedure does and how.
    3. Clarify the base case and it properly handles simple situation(s).

Using approaches from steps 5-7, write the following methods.

  1. Write a method public void add2 (IntNode ls) that doubles the integer stored in each node within the list ls.

  2. Write a method public int findMax (IntNode ls) that assumes list ls is not null and returns the largest integer on the list.

  3. Write a method public int count7s (IntNode ls) returns the number of nodes containing the number 7.

Working with Lists of Strings

In the following exercises, suppose a StringNode is defined as follows:

  public class StringNode {
     protected String data;
     protected StringNode next;

     public StringNode (String item, StringNode next) {
        data = item;
        this.next = next;
     }
     /* getters and/or setters follow */
  1. As a warm up for this section, consider the following method:

       public String longerString (String str1, String str2) {
          if (str2.length < str1.length) {
             return str1;
           } else {
             return str2;
           }
       }
    
    1. Explain (in English) what this procedure does.

    2. Test longerString within Java/Eclipse to illustrate how this procedure works in various circumstances.

  2. Now consider the following recursive procedure longest-on-list that uses procedure longer-string.

      public String longestOnList (StringNode ls) {
         if (ls == null) {
            return null;
           }
         if (ls.getNext () == null) {
            return ls.getData ();
         }
         return (longerString (ls.getData (), longestOnList (ls.getNext () )));
       }
    
    1. Test longestOnList in the following cases:

      • The list ("This" "is" "the" "forest" "primeval")
      • The list ("Wherefore" "art" "thou" "Romeo")
      • The list ("To" "be" "or" "not" "to" "be")
      • The list ("foo")
      • The list ("keep" "it" "short" "and" "sweet")
      • The list ("you" "can" "see" "the" "top")
    2. Write a paragraph that describes how this procedure longest-string works.

    3. Apply longest-on-list to the empty list. Explain why you get the result returned.

With these examples as illustrations, the next four exercises ask you to write your own recursive procedures to solve a variety of problems.

  1. Write a String version of list-of-zeroes—that is, a method replicate that takes two arguments, int size and String item, and returns a list of size elements, each of which is item:

    (replicate 6 "foo") ===> ("foo" "foo" "foo" "foo" "foo" "foo")
    (replicate 1 "computer") ===> ("computer")
    (replicate 0 "help") ===> ()
    
  2. Write a method public boolean isAscending (StringNode ls) that returns true if all successive strings on the list are in dictionary order and false otherwise.

  3. Write a recursive version of a print that takes a list of strings as parameter and prints then (front to back) on separate lines.

  4. Modify the previous method print to obtain a printReverse method that prints the strings on a list from back to front.
    Hint: Once the recursive method of Step 15 is written, printReverse requires very little editing!


created 4 February 1997 by John David Stone
revised 25 January 2009 by Henry M. Walker
revised December 2019 by Henry M. Walker
revised to make some methods static April 3 2020 by Henry M. Walker reorganized and translated from Scheme to Java 1-2 February 2020 by Henry M. Walker
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu.