Lab
- Animating Quicksort
The files you need for this assignment can be
downloaded here.
Contents:
Often, a great way to really understand and learn an algorithm is to
be able to see it in action! Our goal is to be able to animate
the quick-sort algorithm by by using Java's "Abstract Windowing
Toolkit" (Java.awt), and in particular their Graphics package
(java.awt.Graphics).
For motivation, you are free to see our demo, but please don't feel like
you have to reproduce that exact animation. Be creative.
This lab is designed to span over two consecutive lab meetings. In no
way are we suggesting that you need to do any additional work during
the intermediary week outside of lab. We simply feel that we can get
a basic version of the lab done in one sitting, but can do even better
coming back later with a second sitting. Please remember to save your
code from the first week.
We are providing you with an Applet which contains the full code for
quick-sort, but without any of the animation. Your job is to be the
artist!
To be more specific, the program sorts an array of integers with
values from 0 to N-1, which are randomly shuffled before
beginning. The code is modeled after the in-place quick-sort code
from Section 10.3.1 of the text, however it has been specialized to
sort an array of int's rather than a Sequence of
Object's.
The file QuickAnimation.java contains the quick-sort code.
You do not need to modify the existing lines of this sorting method,
however you will want to modify that files by inserting various
animation commands which will allow the user to see what is going on
as the sort progresses.
When the user indicates that the sort should run, the applet
initializes a new popup window for your use as a palette. Of course,
the code we have provided you with does not yet draw on this palette.
By default, if the array has N items, a window is created with width
equal to N and height approximately 1.5 x N. The coordinate
system is set up such that the origin (0,0) is located at the
top-left corner of the screen. Our thought is that you can use
an N x N square to show the values of the array, and that you can use
the extra space below that square to add additional graphics to
display the structure of the recursive calls. If the user would like
to see a magnified view, there is a parameter mag >= 1 which
scales the window to be larger.
The following variables are already defined and initialized for your routines:
- Graphics gimage - this is the Object that you will use
as your palette. For example, you will use the command
gimage.setColor(Color.black) to set the drawing color to black.
- int[ ] A - the array of values.
- int N - the number of items in the data set
(values
will be stored in A[0]...A[N-1])
- int mag - the magnification factor (for those
interested).
We will be making some very basic requirements for the minimal
completion of the lab. The rest of it will be left open-ended for you
to improve your animation as time and creativity permits.
Here is our suggestion for getting going:
- As a test to begin, try to draw any shape on the screen from the beginning
of the quickSort method. This will hopefully let you see how your
commands effect the appearance of the graphics.
- Write code in the beginning of the quickSort method
which graphs the content of the array as follows. For this demo there
are N values, and each value between 0 and N-1 is
represented. This allows you to draw the contents of the array as
follows. Each item can be drawn as a single point (a 1 x 1
rectangle), where the x-coordinate corresponds to the array
index and the y-coordinate corresponds to the value of
the array entry. If the array were properly sorted, such a drawing
will appear as a single diagonal line (if you want this line to start
at the bottom-right corner, your code must adjust for the fact that
the origin is at the top-right corner). As the input is originally
shuffled, there will be a random looking pattern of dots.
- The only way in which the contents of the array are modified by
in-place quicksort is during the "swap" of two items. We would like
for you to make sure that any such swap is properly reflected in the
graphics. One approach would be that whenever the contents of the
array change, you could white-out the entire window and redraw the
contents from scratch. Of course, this involves unnecessary work.
The more efficient approach is to carefully erase the two points
representing the items before they are swapped, and then to draw in
the new representation of the two items. If you add such code in
whenever a swap takes place, you should be able to run quicksort and
see it in action!
Getting to this point will be deemed as success for week 1.
There are lots of ways to improve the animation in order to better
show the workings of quicksort.
For the second week, you should go on to implement at least one of the
following improvements:
- Add graphics to animate the partitioning part of the method. For
example, you could use colored lines below the rest of the graph to
mark the position of the variables leftIndex and
rightIndex that march towards each other while partitioning
around the pivot element. Or you may want to highlight the choice of
pivoting element by temporarily drawing a horizontal line through that
item.
-
In the rectangular area below the display of the array contents, try
to give a view of the recursive structure of the algorithm. This can
be done in many different ways.
- At minimum, you can draw a separate horizontal line (or bar) to
correspond to each recursive call which is made. In particular, you
can use the left and right index bounds for the recursion to decide
the left and right x-coordinate of the bar. The
y-coordinate can be set based on the extra "depth" parameter
which is given to designate the current size of the recursive stack at
that point.
- You can draw each bar and leave it there, so that at the end of
the time you would see a recursive tree structure similar to some of
those in the text.
- You can draw each bar when the recursion starts, and erase the
bar when the recursion ends. In this way, the animation will show the
currently nested recursive calls while animating.
- You can use a combination of colors to differentiate between the
currently active recursive calls, and the completed recursive calls.
- Use the magnification parameter to give a bigger drawing. For
instance if mag==3, you could draw each item with a 3 x
3 rectangle rather than a 1 x 1 rectangle. Of course you
will have to be careful to properly scale all coordinates used
throughout your graphics.
You can choose to animate in whatever style you wish. If you would
like, you are free to see
our demo, but please don't feel like you have to
reproduce that exact animation. Be creative.
Your code contains a variable gimage which is an
instantiation of the java.awt.Graphics class. You will need
to use this variable to make most graphics call.
The coordinate system for the Graphics object is defined so that the
origin (0,0) is located at the top-left corner of the screen.
Increasing the x-coordinate signifies moving farther to the
right; increasing the y-coordinate signifies moving farther
downward.
The Graphics package is designed so that there is always a current pen
color, though this choice of color can be changed as needed. At any
point, you are allowed to draw basic shapes by specifying the relevant
geometry in the coordinate system. When you draw on a graphics, you
will be drawing on top of whatever you have previously drawn on that
part of the coordinate system. For example, if you want black writing
on a blue square, you will need to first draw the blue square and then
draw the black text. Doing things in the reverse order will have the
effect of painting the blue square overwriting the black text.
Full documentation for the latest version of the
Java.awt.Graphics package can be found online at,
http://java.sun.com/j2se/1.3/docs/api/java/awt/Graphics.html
Highlights of java.awt.Graphcis:
- Colors - Java offers a set of 13 predefined colors such as
Color.black, Color.blue, Color.white, and
so on. Additionally, you can define your own color by specifying its
red, green, and blue components each as values between 0.0 and 1.0.
To define such a new color, use the command new Color(r,g,b).
- A Graphic always maintains a current pen color which is used for
drawing. The color can be set with a method such as:
gimage.setColor(Color.black)
or
gimage.setColor(new Color(0.7, 0.5, 0.2))
- Erasing something on the screen can be accomplished by repainting
the object using the background color. (in our case,
Color.white)
- Most standard geometric shapes can be drawn, either as outlines,
or as filled solids. Examples include:
- gimage.drawLine(x1,y1,x2,y2)
- gimage.drawRect(x,y,width,height)
This draws a
(non-filled) rectangle, with top-left corner (x,y).
- gimage.fillRect(x,y,width,height)
This draws a
filled rectangle, with top-left corner (x,y).
- fillRect(x,y,1,1) - this draws a point (a rectangle) at
the point (x,y).
- gimage.drawOval(x,y,width,height)
This draws a
(non-filled) oval, lying in the imaginary rectangle with top-left
corner (x,y).
- gimage.fillOval(x,y,width,height)
This draws a
filled oval, lying in the imaginary rectangle with top-left
corner (x,y).
- gimage.drawString(str,x,y)
This draws the text 'str'
where (x,y) is the coordinate of the top-left corner of
the string's bounding box.
We have provided a routine Redraw() which you must call
every time you want your Graphics changes to be redisplayed on the
screen. We have also placed a delay inside this routine in order to
intentionally slow down your animation (based on a user parameter in
the applet).
Although you will only need to modify one file
(QuickAnimation.java), you will need to
download several files we provide.
You do not have to submit any files electronically. You should
instead make a printout of the modified file
QuickAnimation.java and make sure your name is written
clearly at the top of the file. Do this for each of the two weeks, to
mark your relative progress.
Last modified: 24 October 2002