| 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.
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).
The first 3 steps of this lab involve using recursion in numeric computations—first reviewing an example and then writing some code.
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))
}
}
Run power on several test cases that illustrate that this
procedure performs as indicated by the pre- and post-conditions.
Write a paragraph to explain how power accomplishes its task.
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!
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
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 ).
Lists can be defined in several ways. A particularly common
and useful approach for a list of type E items is recursive:
null is a list.
item is a datum of type E, and
if ls is a list, then (item ls) is a
list.
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 */
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));
}
}
descendingList with several beginning values and
observe what happens.
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) ===> ()
Consider the following methods that process data
in an IntNode.
public int challenge1 (IntNode ls) {
if (ls == null) {
return 0;
} else {
return ls.getData() + challenge1 (ls.getNext());
}
}
public void challenge2 (IntNode ls) {
if (ls == null) {
return;
} else {
int item = ls.getData ();
ls.setData = item*item;
challenge2 (ls.getNext ());
}
public int challenge3 (IntNode ls) {
challenge3 (ls, 0);
}
public int challenge3helper (IntNode ls, int number) {
if (ls == null) {
return number;
} else {
return (challenge3helper (ls.getNext (), 1+number);
}
}
For each of these methods, answer the following:
Using approaches from steps 5-7, write the following methods.
Write a method public void add2 (IntNode ls) that
doubles the integer stored in each node within the
list ls.
Write a method public int findMax (IntNode ls) that
assumes list ls is not null and returns the
largest integer on the list.
Write a method public int count7s (IntNode ls) returns the
number of nodes containing the number 7.
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 */
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;
}
}
Explain (in English) what this procedure does.
Test longerString within Java/Eclipse to illustrate how this procedure works in various circumstances.
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 () )));
}
Test longestOnList in the following cases:
("This" "is" "the" "forest" "primeval")
("Wherefore" "art" "thou" "Romeo")
("To" "be" "or" "not" "to" "be")
("foo")
("keep" "it" "short" "and" "sweet")
("you" "can" "see" "the" "top")
Write a paragraph that describes how this procedure longest-string works.
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.
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") ===> ()
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.
Write a recursive version of a print that takes a
list of strings as parameter and prints then (front to back) on
separate lines.
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 |
|
| For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |