1. Recursion and Drawing
Example -- Drawing a row of circles
Drawing a row of circles was one of the first examples that we used to illustrate a basic Java construct: the
while loop. The goal was to draw a horizontal row of
n touching circles of the same
radius; the left-most circle is centered at coordinates
x, y
Here is a slightly modified version of the original versions for drawing overlapping circles (so only
startX+radius):
void drawCirclesRow( double startX, double startY, double radius, int n )
{
// as long as there are circles to draw
while ( n > 0 )
{
canvas.drawCircle( startY, startY, radius, "red" );
startX = startX + radius;
n = n - 1;
}
}
This process can also be described recursively, since after we paint the first circle we are still left with the task of drawing a row of circles (but the new row has one fewer circles and starts at a new starting location.)
We first consider what represents the
easy case. For this problem the easy case is when we are asked to draw a single circle: all we have to do is paint the circle and we are done.
The hard case is when
n > 1, i.e. when we are asked to draw more then one circle in the row. In this case we can
paint the first circle and hope that somehow there is a way to draw a row of the remaining
n-1 circles.
The outline of the drawing process is:
To draw a row of n circles starting at given x and y:
if n == 1:
1. draw one circle at the given x,y coordinates
else:
2. draw a circle at the given x,y coordinates
3. draw a row of n-1 circles starting
just to the right of the circle in step 2.
The drawing process described above is
recursive: step 3 in the description of how to draw a row of circles asks us to
draw a row of circles. Fortunately, each time we are asked to draw a row of one fewer circles, so eventually, we will get to the easy case.
Here is the corresponding Java code:
void drawCirclesRow( double startX, double startY, double radius, int n )
{
// if there are circles to draw
if (n == 1)
{
canvas.drawCircle( startX, startY, radius, "blue" );
}
else
{
canvas.drawCircle( startX, startY, radius, "red" );
drawCirclesRow( startX + radius, startY, radius, n - 1 );
// ^^^^^^^^^^^^^^^ ^^^^^
// just as above: new value for startX and new value for n
}
}
We can actually do even less work. Right now we consider it "easy" when we are asked to draw only one circle. However, it would be much easier if are asked to draw no circles.
The code can then be transformed into:
void drawCirclesRow( double startX, double startY, double radius, int n )
{
// do nothing if 0 circles need to be drawn -- EASY!!
if (n == 0)
{
}
else
{
canvas.drawCircle( startX, startY, radius, "red" );
drawCirclesRow( startX + radius, startY, radius, n - 1 );
}
}
In the code above the real work is done when at least one circle needs to be drawn. There is no need to keep the case
(n == 0) since no code is executed in this case.
The final code is:
void drawCirclesRow( double startX, double startY, double radius, int n )
{
// only do something, if at least one circle needs to be drawn
// when n becomes 0, nothing is done/drawn
if (n > 0)
{
canvas.drawCircle( startX, startY, radius, "red" );
drawCirclesRow( startX + radius, startY, radius, n - 1 );
}
}
Comparison
Consider the two versions below and suppose that we run both in the same way:
drawCirclesRow( 100, 200, 20, 5 )
1. Would we see identical drawings?
2. Where will the blue circle be drawn?
3. When will the blue circle be drawn?
void drawCirclesRow( double startX, double startY, double radius, int n )
{
if (n == 1)
{
canvas.drawCircle( startX, startY, radius, "blue(red)" ); // BLUE circle
}
else
{
canvas.drawCircle( startX, startY, radius, "red(blue)" ); // RED circle
drawCirclesRow( startX + radius, startY, radius, n - 1 );
}
}
This version is the same as the one above but switched the order of lines inside "else":
void drawCirclesRow( double startX, double startY, double radius, int n )
{
if (n == 1)
{
canvas.drawCircle( startX, startY, radius, "blue(red)" ); // BLUE circle
}
else
{
drawCirclesRow( startX + radius, startY, radius, n - 1 );
canvas.drawCircle( startX, startY, radius, "red(blue)" ); // RED circle
}
}