![]() Graphic by Keith Ohlfs |
Forms of Iteration |
[CS111 Home Page] [Syllabus] [Lecture Notes] [Assignments] [Labs] [Programs] [Documentation] [Software Installation] [FAQ] [CS Dept.] [CWIS]
while
loops, and for loops.
We will use the task of reversing a list as an example to
illustrate how different forms of iteration are related to
each other and to recursion. A recursive implementation of
reverse is given below.
public static IntList reverse (IntList L) {
if (isEmpty(L)) {
return empty();
} else {
return postpend(reverse(tail(L)), head(L));
}
}
public static IntList postpend (IntList L, int n) {
if (isEmpty(L)) {
return prepend(n, empty());
} else {
return prepend(head(L), postpend(tail(L), n));
}
}
The recursive method reverse above not only calls
itself, but it also must do something to the result it gets
from calling itself. The answer from the recursive call to
reverse is used as a parameter to postpend.
We call postpend a pending operation in the
recursion. Iteration, on the other hand, does not have pending
operations. Each pass through the iteration is a complete set
of calculations. To achieve this, extra variables are usually
necessary to keep track of the state of things during the
iteration and to hold the partial state of the answer we
are putting together.
To solve the problem of reversing a list iteratively, we need
a different reverse strategy. An alternative technique for
reversing a list is to follow the strategy one would use in
reversing a pile of cards: form a new pile by iteratively
removing the top card of the original pile and putting it on
the new pile. When there are no more cards in the original pile,
the new pile contains the cards in reverse order from the original pile.
To implement this iterative strategy, we need to keep track
of the list we are reversing, and the result we
are building. Given a list L1=[1,2,3,4],
the iteration table for reverse(L1) would be
| list | result |
|---|---|
[1,2,3,4] |
[] |
[2,3,4] |
[1] |
[3,4] |
[2,1] |
[4] |
[3,2,1] |
[] |
[4,3,2,1] |
For the tail-recursive implementation of reverse,
we see that we need an auxiliary method (which we call
reverseTail) because reverse has
one parameter list but the iteration table has two
state variables (list and result). The implementation
with comments is given below.
// main method
public static IntList reverse(IntList list) {
// returns the result of the auxiliary method
// the parameters of the auxiliary method are the
// values in the first column of the iteration table
return reverseTail(list, empty());
}
// tail-recursive auxiliary method
// notice there is one parameter for each state variable
// (column) of the iteration table
public static IntList reverseTail(IntList list, IntList result) {
if (isEmpty(list)) { // base case: when to stop
return result; // this is the state variable which holds the answer
} else { // general case: do a recursive call
// notice there are no pending operations!
// the next value of list is tail(list)
// the next value of result is prepend(head(list), result)
return reverseTail(tail(list), prepend(head(list), result));
}
}
while loopswhile loop is a form of iteration
which does not involve recursion. Instead, the syntax
creates a loop which is a body of code which is
repeated over and over again while some condition is true.
The loop is terminated when the specified condition is false.
The formal syntax for a Java while
loop is
while (continuation-condition) {
loop body statements
}
The relationship between a while loop
and the iteration table and tail-recursive implementation
is as follows:
while loop involves a
continuation condition. This is the opposite
of the stop condition which is the base case of the
tail-recursive or recursive implementations.
while loop implementation does not
involve an auxiliary method. Instead, all state variables
in the iteration table which are not parameters of the method
are initialized at the beginning of the method.
while loop implementation
of a method, we can derive the iteration table by creating
a column for each parameter in the method and
for each state variable which is initialized outside the
loop and updated inside the loop.
Variables which are initialized outside the loop and not
modified within the loop are not needed in the iteration table.
For the while loop implementation of
reverse, we see that we need to initialize
one state variable result at the beginning of the method
because reverseWhile has one parameter list
but the iteration table has two state variables (list and
result). The implementation with comments is given below.
public static IntList reverseWhile(IntList list) {
IntList result = empty(); // initialize state variable
while (!isEmpty(list)) { // continuation condition is opposite of base case
// update state variables in body of loop
// must update result before list because
// it depends on the original value of list
result = prepend(head(list), result);
list = tail(list);
} // end of loop
return result; // answer is returned when loop is finished
}
for loopsfor loop is a form of iteration which
is just a while loop written in a more compact
syntax. In computer science, we call this phenomenon syntactic
sugar. So, a for loop is syntactic
sugar for a while loop. Every
for loop can be written as a
while loop, and vice versa, but it may not
always be easy to do so. for loops are generally
used with arrays which we will be studying in the near
future. Their syntax is useful in situations in which there is a
counter which is incremented or decremented with each pass
through the iteration. The formal syntax for a Java
for loop is
for (counter-initialization; continuation-condition; counter-update) {
loop body statements
}
The relationship between a for loop
and while loop implementation is as follows:
for loop is equivalent to
the following Java while loop:
counter-initialization
while (continuation-condition) {
loop body statements
counter-update
}
for loop involves a
continuation condition. This is the opposite
of the stop condition which is the base case of the
tail-recursive or recursive implementations. The continuation
condition of the for and
while loops can be exactly the same.
for loop counter. If the counter
is not a parameter of the method, it gets initialized in the
counter-initialization part of the for
loop instead of at the beginning of the method.
for loop instead of at the end of the
loop body.
for loop are initialized
at the beginning of the method.
for
loop specifications blank. However, the semicolons must be in
place to identify the three parts. An infinite loop can be created
by the following syntax:
for ( ; ; ) { // no conditions
loop body statements // these statements run forever!
}
for loop specifications.
Statements should be separated by commas. For example,
for (int i=0, IntList L=list ; (!isEmpty(L) && (i<5)) ; i=i+1, L=tail(L)) {
loop body statements
}
for loop implementation
of a method, we can derive the iteration table by creating
a column for each parameter in the method, for
each counter, and for each state variable which
is initialized outside the loop and updated inside the loop.
Variables which are initialized outside the loop and not
modified within the loop are not needed in the iteration table.
For the for loop implementation of
reverse, determining what the counter will
be is a bit tricky since there aren't any numbers which are
incrementing or decrementing. Instead, we pick the IntList
list to be our counter because it is shrinking with each
pass through the iteration. Since list is a parameter
of our method, it doesn't need to be initialized. Therefore,
there will be nothing in the counter-initialization
part of our for loop.
The implementation with comments is given below.
public static IntList reverseFor(IntList list) {
IntList result = empty(); // initialize state variable
// no counter-initialization
// loop continues while list is not empty
// list becomes tail(list) with each pass through iteration
for ( ; !isEmpty(list); list=tail(list)) {
// update state variables in body of loop
result = prepend(head(list), result);
} // end of loop
return result; // answer is returned when loop is finished
}