CMPS 144L Spring 2019
Week #9 Lab: Recursion

Activity #1: Numeral to Number Conversion

Here we confine ourselves to considering decimal integer numerals, by which we mean non-empty character strings (i.e., values of type String) containing only digit characters (i.e., char values in the range '0' .. '9').

Examples of numerals (expressed as literal Strings, as might appear in a Java program) are "7" and "80236".

The Integer.parseInt() method has as its purpose to translate such numerals to their corresponding numbers (i.e., values of type int). Thus, for example, it translates the numeral "5302" to the int value 5302.

As an academic exercise, in this activity you are to develop a method that performs the same translations. In addition, your solution must be recursive, meaning that it must involve a method that calls itself.

A recursive solution to this problem can be based upon the following ideas. Let #() be the (mathematical) function mapping (decimal integer) numerals into their corresponding integer values. For example, #("529") = 529. We can also imagine that # is overloaded so that it can be applied to digit characters, so that, for example, #('3') = 3.

Let x be the numeral x1x2...xn-1xn, (with each xi being a digit character, of course).

If n=1 (i.e., the length of x is one), then #(x) = #(x1). That is, translating x into a number reduces to translating its lone digit into a number (which is easy).

If, on the other hand, n>1:

#(x) = #(x1x2...xn-1xn) = 10 × #(x1x2...xn-1) + #(xn)

For example,

  #("286")  
= 10×#("28") + #('6') (applied # to "286")
= 10×(10×#("2") + #('8')) + #('6') (applied # to "28")
= 10×(10×#('2') + #('8')) + #('6') (applied # to "2")
= 10×(10×2 + 8) + 6 (applied # to each of '2' , '8', and '6')
= 10×(20 + 8) + 6 (computed 10×2)
= 10×28 + 6 (computed 20+8)
= 280 + 6 (computed 10×28)
= 286 (computed 280+6)

Having understood all that, supply the body of the parseIntRec() method in the ParseIntRecTester Java application that is provided. Use the application to test your method for correctness. Entering an empty string at the prompt will cause the program to terminate.


Activity #2: Exponentiation

An efficient approach to computing a (real number) base x raised to a (nonnegative integer) power n follows from this recursive characterization of xn:

xn = { 1if n = 0
(x2)n/2if n>0 and n is even
xn-1 × xotherwise

Using this, supply the body of the xToTheNRec() method in the ExponentiationTester Java application that is provided. Use the application to test your method for correctness. Entering a negative exponent at the prompt will cause the program to terminate.

For each x and n that the user enters, the program will display both the value computed by your method and by the Math.pow() method. If the two values are not very close, it is a strong indication that your method is in error.

The program also displays the number of multiplication operations performed by your method. (Well, you are responsible for updating the relevant variable appropriately within your method.) If your method is a faithful implementation of the recursive equation given above, the number of multiplications should be at most 2×lg(n) (i.e., twice the logarithm, to the base 2, of the exponent). Compare that to the number of multiplications that you would perform by following the "naive" approach, which is n-1.


Activity #3: Greatest Common Divisor

Note: The next three paragraphs are taken largely from Wikipedia's Euclidean algorithm entry. End of note.

The Euclidean algorithm (described by the Greek mathematician Euclid in his mathematical treatise Elements in 300 BC) is based on the principle that the greatest common divisor (GCD) of two numbers does not change if the larger number is replaced by its difference with the smaller number. For example, 21 is the GCD of 252 and 105, and the same number 21 is also the GCD of 105 and 252 - 105 = 147. Since this replacement reduces the larger of the two numbers, repeating this process gives successively smaller pairs of numbers until the smaller of the two numbers becomes zero. When that occurs, the larger one is the GCD of the original two numbers.

The version of the Euclidean algorithm described above (and by Euclid) can take many subtraction steps to find the GCD when the larger of the given numbers is much bigger than the other. A more efficient version of the algorithm shortcuts these steps, instead replacing the larger of the two numbers by its remainder when divided by the smaller of the two. (With this version, the algorithm stops when that remainder is zero.)

With this improvement, the algorithm never requires more steps than five times the number of digits (base 10) of the smaller integer. This was proven by Gabriel Lame in 1844, and marks the beginning of computational complexity theory (which is concerned, in part, with how much "work" an algorithm performs as a function of how much input data it is given).

In summary (assuming that both k and m are nonnegative and their sum is strictly positive):

If m is zero, then the GCD of k and m is k; otherwise, the GCD of k and m is the GCD of m and k % m.

Using this information, supply the body of the gcdViaRec() method in the GCD_Tester Java application that is provided. Use the application to test your method for correctness. Entering a negative value for k causes the program to terminate.


Activity #4: Link1 Structures

Enter a nonnegative integer: 9

Building a list containing 0..8

Computing length of the list...
Length of list is 9

Printing elements in list...
0 1 2 3 4 5 6 7 8

Printing elements in reverse order...
8 7 6 5 4 3 2 1 0

Goodbye.
Link1RecTester is a Java application that prompts the user to enter a nonnegative integer, call it n. It then assembles a linked list of nodes, each an instance of the Link1 class with which you are familiar, containing the Integer values 0, 1, ..., n-1, in that order.

It then reports the length of the list, prints the elements of the list, and, finally, prints the elements of the list in reverse order. To the right is what you should see if you run the program and provide an input of 9.

The methods that compute the length of the list (lengthOf()), print its elements (printList()), and print its elements in reverse order (printReverseList()) are all STUBS waiting for you to complete them. You are to do so, making sure that each one is recursive. That is, there should be no loops.