CS 99

Summer 2001������������������������������������������������������������������������������ ������ 7.16

 

 


Lecture Notes 5

 

Combining Control Structures

         An algorithm can contain many control-flow constructs in non-trivial combinations.

         Sequencing, branching, and looping can be interleaved and nested within each other.

         For example, algorithms can contain nested loops.A loop inside a loop can take on the form �do A exactly N times� where A itself is of the form �Repeat B until Q�

         The A part of the outer loop can contain many further segments each of which can, in turn, employ additional sequencing, branching, and looping constructs, and the same goes for the inner loop.Thus there is no limit to the potential intricacy of one�s algorithms.

 

Patterns

         Experienced programmers often have �templates� mentally available for particular kinds of problems.Some kinds of situations show up so often that it�s useful to carry these patterns of code around in your head, so that when these situations arise, the program (or at least parts of it) can more or less write itself.

         For instance, many of you are finding Lab 6 a bit challenging.It really isn�t (in my opinion) because the different parts of the lab are really asking you to do the same things over and over; once you grasp the pattern that emerges, most of you should fly through the assignment.

         What are some of the kinds of patterns tested in Lab 6?

 

A pattern for iterating n times:

 

/* Do whatever n times: Version 1 */

int j = 1;

while ( j <= n ) {

���� whatever

���� j = j + 1;

}

 

         Think of such a pattern as a whole: �do whatever n times�

         whatever can refer to variable or it may not

         There�s nothing special about these variables: any variable can be used instead of j and n.

         j is a counter variable: it�s purpose is make sure the loop body executes precisely n times.

         Note that it isn�t necessary to count from j = 1 to j = n, nor do we need to count upwards all the time.The following code snippets will work just as well for iterating something n times:

 

/* Do whatever n times : Version 2*/

int j = 0;

while ( j < n ) {

���� whatever

���� j = j + 1;

}

 

/* Do whatever n times: Version 3*/

int j = n;

while ( j > 0 ) {

���� whatever

���� j = j - 1;

}

 

         Note carefully the stopping conditions in these new versions.In Version 2, because j is starting at 0 and not 1, the stopping condition must be strictly j < n, and not j<= n.If we go all the way to n, then starting from 0, we will have counted n+1 times, not n times.

 

         The same is true for Version 3.The stopping condition must be j > 0 and not j>=0.

 

A pattern for reading values until a stopping (sentinel) value is encountered

/* Do whatever repeatedly until the user enters -1 */

TokenReader in = new TokenReader( System.in );

int val = in.readInt();

while ( val != -1 ) {

���� whatever

���� val = in.readInt();

}

 

         In this circumstance, we don�t use, nor do we need, a counter variable to stop the loop.That�s because we don�t know how long the input will actually be.

         We may introduce counter variables to keep track of other things you might be interested in, but we don�t need one to stop the loop itself. (Indeed, in the Hi-Lo Game from Lab 6, you use a counter variable to keep track of the number of guesses the user has made.But that counter variable is not used to stop the game.)

         Since our loop doesn�t have a counter variable, the loop body must contain a statement that affects the loop condition in some other way (it must, otherwise, the loop will never end).In this case, instead of having j count up until it hits n, we use TokenReader to keep reading in values. Each value entered is checked against the stopping value in the Boolean conditional.When the correct stopping value is read, the loop ends.

         The algorithm is not guaranteed to end!If the user never enters �1, the loop will not stop.

         Again think of such a pattern as a whole: �do whatever an unknown number of times until a particular stopping value is read�

         Usually we don�t think of the stopping value as a part of the input data itself.It�s considered separately from the data, it�s merely a stopping condition.For instance, in the code above, if the user immediately enters �1 as the first value, the loop body never execute; �whatever� will not be performed.

         When you choose the stopping condition, try to choose some value that�s outside of the data range you�re looking at.So if you�re reading in positive numbers, let your stopping value be negative.

         It also isn�t necessary to have just one stopping value (and usually it isn�t).For instance, if the code snippet above was for reading in non-negative values (including 0) for the data, we can use the following bit of code just as well:

 

/* Do whatever repeatedly until the user enters -1 */

TokenReader in = new TokenReader( System.in );

int val = in.readInt();

while ( val >= 0 ) {

whatever

 


����
val = in.readInt();

}

 

         This is actually preferable to the previous version because, assuming whatever is expecting only non-negative numbers, this loop condition guarantees that whatever will never encounter a negative number (the one before would have kept going if the user had entered in say �10).

 

 

Using the Patterns

Problem 1:

An integer n is given as input data.Output a list of the perfect squares between 1 and n^2 inclusive.

Solution 1:
int n = in.readInt();

int j = 1;
/* Output on each line the perfect squares between 1 and n^2 inclusive */

while ( j<= n) {
���� /* Output the perfect square of j */

System.out.println( j*j );

 
����



j = j+1;

}

 

The output for this program segment for an input of 5 is:

 

1
4
9
16
25

Comments:

         Here, the whatever is output the perfect square of j, the counter variable.

         Note that 36 is not printed because j gets the value 6 after it�s printed 25 on the screen, and the loop ends before it reads the println() statement.

 

Problem 2:

An integer m is given as input data.Output a line of m asterisks (*�s).

Solution 2:

int m = in.readInt();

int j = 1;
/* Output a line of m asterisks */

while ( j<= m) {
���� /* Output an asterisk, leave the cursor on the same line */

System.out.print( �*� );

 


����
j = j+1;

}

 

For an input of 5, the output for this segment is

 

*****

Comments:

         Here the whatever is to print a single asterisk and leave the cursor on the same line.

         Notice that the stars are all on one line because we�re using a print() statement instead of a println() statement.

 

 

 

Problem 3 (perfect numbers again!):

A number is �perfect� if it equals the sum of its divisors, including 1 but excluding itself.An integer p is given as input data.Output �perfect� if it�s perfect, and �not perfect� if it�s not.

Solution 3.

int p = in.readInt();

int sum = 0;

int j = 1;

while ( j < p ) {

/* if j divides p add it to the sum of the divisors so far */
if (p %j == 0 )
���� sum+=j;

 
�����

 

 

 

 

j++;

}

 

Comments:

         At first blush, this doesn�t seem like a candidate for any of our patterns.But it is, because in order to find out the sum of the divisors, we have to loop through all the possible numbers from 1 to p-1 to see which ones actually divide p.

         Hence, we have to do something (in this case, does the number divide p? if so, add it to the running sum) a set number of times (p-1).The thing that makes this one more interesting than the previous two is that the whatever part involves the counter variable, j, itself.

 

Problem 4:

An integer n is given as input data.Output a triangle of asterisks with base and height n, e.g., if n is 3, the following is output on the screen:


*

**

***

 

Solution 4:

int n = in.readInt();

int j = 1;

while ( j<= n ) {

���� /* output a line of j *�s */

int k = 1;

while ( k <= j ) {

���� System.out.print(� * � );

���� k = k+1;

}

 
���������






j = j+1;

}

Comments:

         This one is more involved because whatever is itself a loop.

         But notice! The whatever part is written in precisely the same way as the outer loop, because it�s doing the same thing!In the whatever part we�re doing something a set number of times: in fact, we�re printing an asterisk j times! Well, isn�t that just how we described the pattern for doing whatever n times? Now the n is a j, but that�s no biggie! (What�s in a name? That which we call a rose by any other name would still smell the same � )