import draw.*; /* --- CSU213 Spring 2005 Lecture Notes --------- Copyright 2005 Viera K. Proulx Lecture 9: All people are equal, but some are more equal than others... Part 2 */ /* Goals: - learn to determine the equality of two self-referential data - learn to sort lists Our remaining task is to sort the list of CDs. We will sort them by the number of tracks, though there are obviously better choices. 1. Problem analysis. The method 'sort' only needs the list to be sorted. 2. Purpose and Header. // sort this list of CDs in ascending order of the number of tracks abstract ALoCD sort(); This method needs to be defined in every subclass of the ALoCD class. 3. Examples. mtcd.sort() --> new MTLoCD() list1.sort() --> list1 list4.sort() --> new ConsLoCD(pearl, new ConsLoCD(boston, new ConsLoCD(help, new ConsLoCD(tool, mtcd)))) 4. Template. Again, there is no data in MTLoCD, so we only need a template for the class ConsLoCD: ... this.first ... ... this.rest ... ... this.rest.sort() ... 5. Body. As usual we try to do the simple case first. class MTLoCD: ------------- An empty list is sorted, so this is a trivial case: ALoCD sort(){ return this; } class ConsLoCD: --------------- ... this.first ... ... this.rest ... ... this.rest.sort() ... Reading aloud the purpose statement for 'this.rest.sort()' we get: 'sort the rest of this list of CDs in ascending order of the number of tracks' So all that reamins is to insert the first item into a sorted rest of the list. We use a helper method: // insert the given CD into this sorted list ALoCD insert(CD cd) and with the help of this method, the body for the 'sort' becomes: return this.rest.sort().insert(this.first); ---------------------------------------------------------------------------- We now work on the helper method 'insert'. we already have the purpose and header. Examples. mtcd.insert(tool) --> new ConsLoCD(tool, mtcd) list1.insert(pearl) --> new ConsLoCD(pearl, list1) list1.insert(tool) --> new ConsLoCD(help, new ConsLoCD(tool, mtcd)) new ConsLoCD(pearl, new ConsLoCD(boston, new ConsLoCD(tool, mtcd))).insert(help) --> new ConsLoCD(pearl, new ConsLoCD(boston, new ConsLoCD(help, new ConsLoCD(tool, mtcd)))) Template and Body. class MTLoCD: ------------- The result is always a list with one item: return new ConsLoCD(cd, this); class ConsLoCD: --------------- We use the earlier template for the class ConsLoCD ... this.first ... ... this.rest ... ... this.rest.sort() ... However, we cannot add ... this.rest.insert(CD ...) to the template, because it requires that the instance that invokes the method be already sorted. But we can use this.rest.sort() instead, to invoke the 'insert' method: ... this.rest.sort().insert(CD ...) ... Reading aloud the combined purpose statement for 'this.rest.insert(CD ...)' we get: 'insert the given CD into the sorted rest of this sorted list' If the given CD has fewer tracks than the first item in the list, the resulting list is just new ConsLoCD(cd, this) otherwise, the first item of the sorted list is the first item of the list we are instering into, and the rest consists of the given CD inserted into the rest of the list: new ConsLoCD(this.first, this.rest.insert(cd)) and the body of the method is: if (cd.tracks < this.first.tracks) return new ConsLoCD(cd, this); else return new ConsLoCD(this.first, this.rest.insert(cd)); */ // The final code is: /* ; ; ; ; ;;;; ; ; ; ; ; ; ; ; ; ; ;;; ;; ; ;;; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ;;;; ;;; ;; ; ;;;; ; ; ; */ /* +-----------------------+ | CD | +-----------------------+ | String title | | int tracks | +-----------------------+ | boolean same(CD that) | +-----------------------+ */ // to represent a CD class CD { String title; int tracks; CD(String title, int tracks) { this.title = title; this.tracks = tracks; } boolean same(CD that){ return this.title.equals(that.title) && this.tracks == that.tracks; } } /* +-------+ | ALoCD | +-------+ +-------+ / \ --- | ----------------- | | +--------+ +------------+ | MTLoCD | | ConsLoCD | +--------+ +------------+ +--------+ | CD first | | ALoCd rest | +------------+ */ // to represent a list of CDs abstract class ALoCD { // determine whether this list of CDs is the same as the given one abstract boolean same(ALoCD that); // determine whether this list is the same as given MTLoCD list abstract boolean sameMTLoCD(MTLoCD other); // determine whether this list is the same as given ConsLoCD list abstract boolean sameConsLoCD(ConsLoCD other); // sort this list of CDs in ascending order of the number of tracks abstract ALoCD sort(); // insert the given CD into this sorted list abstract ALoCD insert(CD cd); // produce a list of all long CDs (> t10 tracks) in this list abstract ALoCD longCDs(); } // to represent an empty llist of CDs class MTLoCD extends ALoCD { MTLoCD() {} // determine whether this list of CDs is the same as the given one boolean same(ALoCD that){ return that.sameMTLoCD(this); } // determine whether this list is the same as given MTLoCD list boolean sameMTLoCD(MTLoCD other){ return true; } // determine whether this list is the same as given ConsLoCD list boolean sameConsLoCD(ConsLoCD other){ return false; } ALoCD sort(){ return this; } ALoCD insert(CD cd){ return new ConsLoCD(cd, this); } ALoCD longCDs(){ return this; } } // to represnet a non-empty list of CDs class ConsLoCD extends ALoCD { CD first; ALoCD rest; ConsLoCD(CD first, ALoCD rest) { this.first = first; this.rest = rest; } // determine whether this list of CDs is the same as the given one boolean same(ALoCD that){ return that.sameConsLoCD(this); } // determine whether this list is the same as given MTLoCD list boolean sameMTLoCD(MTLoCD other){ return false; } // determine whether this list is the same as given ConsLoCD list boolean sameConsLoCD(ConsLoCD other){ return this.first.same(other.first) && this.rest.same(other.rest); } ALoCD sort(){ return this.rest.sort().insert(this.first); } ALoCD insert(CD cd){ if (cd.tracks < this.first.tracks) return new ConsLoCD(cd, this); else return new ConsLoCD(this.first, this.rest.insert(cd)); } ALoCD longCDs(){ if (this.first.tracks > 10) return new ConsLoCD(this.first, this.rest.longCDs()); else return this.rest.longCDs();} } class Examples { Examples(){} CD help = new CD("Help", 12); CD pearl = new CD("Pearl", 8); CD tool = new CD("Tool", 13); CD boston = new CD("Boston", 10); ALoCD mtcd = new MTLoCD(); ALoCD list1 = new ConsLoCD(this.help, this.mtcd); ALoCD list2 = new ConsLoCD(this.pearl,this.list1); ALoCD list4 = new ConsLoCD(this.tool, new ConsLoCD(this.boston, this.list2)); // test the method totalTracks boolean testLongCD(){ return this.mtcd.longCDs().same(this.mtcd) && this.list1.longCDs().same(this.list1) && this.list2.longCDs().same(this.list1) && this.list4.longCDs().same(new ConsLoCD(this.tool, new ConsLoCD(this.help, this.mtcd))); } // test the method insert boolean testInsert(){ return this.mtcd.insert(this.tool).same(new ConsLoCD(this.tool, this.mtcd)) && this.list1.insert(this.pearl).same(new ConsLoCD(this.pearl, this.list1)) && this.list1.insert(this.tool).same(new ConsLoCD(this.help, new ConsLoCD(this.tool, this.mtcd))) && new ConsLoCD(this.pearl, new ConsLoCD(this.boston, new ConsLoCD(this.tool, this.mtcd))).insert(this.help).same (new ConsLoCD(this.pearl, new ConsLoCD(this.boston, new ConsLoCD(this.help, new ConsLoCD(this.tool,this.mtcd))))); } boolean testSort(){ return this.mtcd.sort().same(new MTLoCD()) && this.list1.sort().same(this.list1) && this.list4.sort().same(new ConsLoCD(this.pearl, new ConsLoCD(this.boston, new ConsLoCD(this.help, new ConsLoCD(this.tool, this.mtcd))))); } boolean testAll(){ return this.testLongCD() && this.testInsert() && this.testSort(); } }