/* Lab 4 CSU 213 Spring 2006 This lab assignment will give you practice with developing methods for class hierarchies involving union, containment, and self-reference. In addition, we will write comparison methods to build proper test suites in the Examples class. */ // // Part I: Unions & Containment // /* We will use and build on this class hierarchy throughout the lab: +-------------------------------------+ | IShape |<----. |double area() | | |boolean smallerThan(IShape that) | | |IShape zoomIn(int factor) | | | | | | | | | | | | | | +----------------------.--------------+ | /|\ | +----------------+-----------+ | | | | | +-----+-----+ +----+-----+ +---+-----+ | | Circle | |Rectangle | | Overlay | | |Posn center+--.--|Posn nw | |IShape s1|--| |int radius | | |int width | |IShape s2|--' +-----------+ | |int height| +---------+ | +----------+ v +---------------------------+ | Posn | |int x | |int y | |boolean samePosn(Posn that)| +---------------------------+ Now do the following: I(a) Translate this class diagram into Java code. Do not forget your templates & examples! Design the following two methods. For each method, augment the above class diagram with the method headers. I(b) // produce the area of this shape double area() I(c) // determine if this shape's area is smaller than `that' shape's area boolean smallerThan(IShape that) Finally, design one more method: I(d) Design the method `zoomIn'. It consumes a zoom-factor and produces an IShape like `this' one, except larger in both dimensions. Work out examples for each shape to figure out what this means! */ // // Part II: Comparisons for Union & Containment // /* Now we will write comparison methods to determine when a given shape is equal to `this' one. Let's recall how this works for a smaller example: +------------------------------+ | IMedia | |boolean sameMedia(IMedia that)| |boolean sameBook(Book that) | |boolean sameCD(CD that) | +---------------.--------------+ /|\ .--------'----------. +------'-----+ +----'-----+ | Book | | CD | |String title| |int tracks| +------------+ +----------+ The interface contains one `same' method for each class (including the interface itself). Each class that implements the interface must define each of the methods. */ // represent media in the library (a Book or a CD) interface IMedia { // determine if this is the same IMedia as that boolean sameMedia(IMedia that); // determine if this is the same Book as that boolean sameBook(Book that); // determine if this is the same CD as that boolean sameCD(CD that); } /* In the Book class, sameBook(Book that) simply compares this.title with that.title, and in the CD class sameBook(Book that) simply returns false because Books and CDs are never the same. */ // represent a book by its title class Book implements IMedia { String title; Book(String title) { this.title = title; } boolean sameMedia(IMedia that) { return that.sameBook(this); } boolean sameBook(Book that) { return this.title.equals(that.title); } boolean sameCD(CD that) { return false; } } /* Likewise, in the CD class, sameCD(CD that) compares this.tracks with that.tracks, and in the Book class, sameCD(CD that) always returns false. */ // represent a CD by the number of tracks class CD implements IMedia { int tracks; CD(int tracks) { this.tracks = tracks; } boolean sameMedia(IMedia that) { return that.sameCD(this); } boolean sameBook(Book that) { return false; } boolean sameCD(CD that) { return this.tracks == that.tracks; } } /* To tie these pieces together, each class must then implement sameMedia(IMedia that). In order to tell if two media are the same, we need to know two things: 1. Are they instances of the same class? 2. If so, are the fields in `this' equal to the fields in `that'? We let Java answer question 1 for us (in two steps). Suppose we have some IMedia: IMedia m = new ...; IMedia n = new ...; We would like to know if m and n are equivalent. When we say m.sameMedia(n) Java will notice that there are 2 different sameMedia methods (one in Book, another in CD). To decide which one to invoke, it will look up the class of which m is an instance. Suppose m is a Book object. Then Java will execute the sameMedia(..) method inside the Book class. This will, in turn, invoke n.(sameBook(this)) where `this' is the book m. At this point Java knows that m is a Book. But, since n is an IMedia, Java must now look up the class of n to determine which sameBook(..) method to invoke. If n is a CD, we will invoke CD's sameBook(..) and return false. If n is a Book, then we will invoke Book's sameBook(..) and compare the two titles. */ /* II(a) Now it's your turn. Design comparison methods for shapes. We have left room in the diagram above for you to fill in the necessary method headers. Do this before you begin coding. This step involves a lot of code. Work on one method at a time, and design the sameShape method last. */ // // Part III: Lists of IShapes // /* Now we will build lists of IShapes. We will then design methods (1) to compare equality of two lists of shapes (2) to compute the total area of all of the shapes in a list of shapes (3) to zoom all of the shapes in a list of shapes by a given factor (4) to sort a list of shapes in increasing order of their area III(a): Design a class hierarchy for a list of shapes. You must produce the class diagram. Use the ASCII art tool JavE at http://www.jave.de to draw it. Use version 6, not 5. Once you download and start JavE, copy and paste the IShape hierarchy from above into it. Then add the boxes and arrows to represent list of shapes to the diagram. Once you do this, copy and paste the whole thing back into this lab below. */ /* III(b): Design method (1) above to compare lists of shapes for equality. Follow the same pattern that you used to design the methods for shape equality. Once you have tested these methods, use them to write tests for the rest of the methods in this section. */ /* III(c): Design methods (2) and (3) from above: - compute the total area of all of the shapes - zoom all of the shapes by a given factor Test these methods using the comparisons you designed in III(b). */ /* III(d): Design method (4). Use the insertion sort technique as discussed in lecture. Remember that this will require you to write two methods on list of shapes: - One helper method `insert' for inserting a given Shape into a sorted list of shapes. - Another method `insertionSort' that sorts `this' list of shapes. */ // // Part IV (Challenge Problem): Quick Sort // /* What, you're done with Parts I, II, and III already? Then try designing a quickSort method! It ought to behave just like the insertion sort above, but it often runs much faster on large lists. We will illustrate by example how quickSort works: Consider the following list of integers L. L = (list 8 2 7 9 3) We begin by choosing an arbitrary element called the "pivot". For simplicity, we will always choose the first element. So let pivot = 8. We then proceed to partition the rest of the list, (list 2 7 9 3), into two smaller lists. The first list contains those elements smaller than the pivot, and the second list contains those elements larger than the pivot. So let smallerInts = (list 2 7 3) largerInts = (list 9) We sort each of these using a recursive call to quickSort. Then, to build the whole sorted list, we simply append the sorted list of smaller elements to the list of sorted larger elements, sticking the pivot in the middle (hence the name -- the pivot stays put while the other elements "revolve" around it). smallerInts.quickSort() = (list 2 3 7) largerInts.quicksort() = (list 9) pivot = 8 Answer = (append (list 2 3 7) (cons 8 (list 9))) = (list 2 3 7 8 9) That concludes our example. To design quickSort, you will need helper methods for appending lists, for selecting elements smaller than a given element, and for selecting elements larger than a given element. After you've designed and tested quickSort, ponder this: on what kinds of lists will your quickSort perform the worst on (in terms of running-time)? Why? What part of your implementation would you have to improve to avoid performing poorly on these kinds of lists? */