goal
play

Goal First version of linear search Generic Programming Input - PDF document

Goal First version of linear search Generic Programming Input was array of int More generic version of linear search and Input was array of Comparable Inner classes Can we write a still more generic version of linear


  1. Goal • First version of linear search Generic Programming – Input was array of int • More generic version of linear search and – Input was array of Comparable Inner classes • Can we write a still more generic version of linear search that is independent of data structure? – For example, work even with 2-D arrays of Comparable, or List, or ArrayList, etc. 1 2 Minor rewrite of linear search “Obvious” linear search code boolean linearSearch (Comparable[] a, Object v) { boolean linearSearch (Comparable[] a, Object v) { int i = 0; for (int i = 0; i < a.length; i++) while (i < a.length) { if (a[i].compareTo(v) = = 0) return true; if (a[i].compareTo(v) = = 0) return true; return false; else i++; } } Code in red relies on data being stored in a 1-D array. return false; For-loop also implicitly assumes that data is stored in 1-D array. } This code will not work if data is stored in a more general Intuitively, linear search needs to know data structure such as a 2-D array. - are there more elements to look at? - if so, get me the next element 3 4 Intuitive idea of generic linear search Key ideas in solution 4 22 22 -9 4 • Iterator interface Linear search 234 -9 • Linear search written once and for all using Iterator interface • Data class that wants to support linear • Data is contained in some object. • Object has an adapter that permits data to be enumerated in search must implement Iteratorinterface some order. • Implementing Iterator interface • Adapter has two buttons – boolean hasNext(): are there more elements to be enumerated? – We look at several approaches – Object Next(): if so, give me a new element that has not been enumerated so far 5 6 1

  2. Generic Linear Search Iterator version Iterator interface boolean linearSearch(Iterator a, Object v) { while (a.hasNext()) if ((Comparable) a.next()).compareTo(v) = = 0) interface Iterator { return true; boolean hasNext(); return false; Object next(); } void remove(); //we will not use this } Compare with Array version This interface is predefined in Java. boolean linearSearch(Comparable[] a, Object v){ Linear search is written using this interface. int i = 0; Data class must provide an implementation of this interface. while (i < a.length) if (a[i].compareTo(v) = = 0) return true; return false; 7 } 8 Adapter (version 1) How does data class implement Iterator interface? class Crock1 implements Iterator{ private Comparable[ ] a; private int cursor = 0; //index of next element to be enumerated public Crock1(…) { …store data in array a… } Let us look at a number of solutions. public boolean hasNext( ) { return (cursor < a.length); } 1. Adapter code is part of data class public Object next( ) { 2. Taking adapter code out of the data class // may throw ArrayIndexOutOfBoundsException return a[cursor++]; 3. a – d : Putting it back in } public void remove( ) { throw new UnsupportedOperationException( ); } } 9 10 Critique • One solution to resetting the cursor: – Data class implement a method void reset() which • As shown, client class can only enumerate resets all internal cursor(s) elements once! – Method must be declared in Iterator interface – No way to reset the cursor • But we still cannot have multiple enumerations of • Making the data class implement Iterator directly elements going on at the same time is something of a crock because its concern should • Remember: only one cursor per data array… be with data, rather than enumeration of data. • Problem: cannot create new cursors on demand • However, this works for other data structures such • To solve this problem, cursor must be part of a as 2-D arrays. different class that can be instantiated any number of times for a single data object. – 2-D arrays: data class can keep two cursors • one for row • one for column • standard orders of enumeration: row-major/column-major 11 12 2

  3. Adapter (version 2) Sharks and remoras class Shark { protected Comparable[] a; public Shark(…) {…get data into a…} Iterator implementation } Data class is like shark is like a remora. class Remora implements Iterator{ private Shark myShark; private int cursor = 0; public Remora(Shark s) { myShark = s; } Remora teeth public boolean hasNext() { // a in Shark is protected, so accessible return (cursor < myShark.a.length); } public Object next( ) { return myShark.a[cursor++]; } public void remove( ) {…} } Single shark must allow us to hook many remoras to it. 13 14 Critique Client code: Shark s = new Shark(…data…); • Good: Remora r1 = new Remora(s); – Shark class focuses on data, Remora class focuses on Remora r2 = new Remora(s); enumeration linearSearch(r1, v); • Bad: – Remora code relies on being able to access Shark variables (e.g. array a must be made protected ) myShark Shark • What if a was declared private? cursor = 3 • Protected access is less secure than private. – Remora is specialized to Shark but code appears outside Shark class myShark Remora • 2-D array Shark will require a different Remora cursor = 5 • We may change Shark class and forget to update Remora. Remora 15 16 Slightly better code: Shark object creates Remoras in request class Shark { // client code Critique protected Comparable[] a; public Shark(…) {…get data into a…} Shark s = new Shark(…data…); • Good: – Shark code mentions Remora, so person modifying Shark public Iterator makeRemora( ) { // let shark make a Remora // Shark code mentions Remora class Iteratorr1 = s.makeRemora( ); code is at least aware that Remora code depends on this return new Remora(this); class. } // or make our own • Bad: } Remora r2 = new Remora(s); – Clients can still create Remoras without invoking linearSearch(r1, v); makeRemora method class Remora implementsIterator { private SharkmyShark; • Better to have language construct to enforce such a convention … • Better to force them to use Iterator, not Remora } – Code in separate files, but closely intertwined: • Remora used in exactly one place: inside Shark.makeRemora() see iterator-2-outside files 17 18 3

  4. Idea: Move Remora Closer An Old Idea: In Same File • Want Remora to be as close as possible to • Problem: Compiler prefers to have one class the one single place that uses it. per file • What does this mean? – How could it know where to find Remora code during compilation? – In same file? – In same class? – In same method? – On same line? 19 20 Make it Static: Nested Classes Better Idea: In Same Class class Shark { private Comparable[ ] a; // client code • Let’s make Remora class a “member” of public Iterator makeRemora( ) { return new Remora(this); Shark s = new Shark(…data…); Shark class } – Should it be static or not? // let shark make it for us public static class Remora //nested class Iteratorr2 = s.makeRemora( ); – Should it be public or not? implements Iterator{ Shark myShark; // make our own Remora int cursor = 0; Remora r1 = new Shark.Remora(); // same code, but has access // to private member myShark.a linearSearch(r2, v); public Object next( ) { return myShark.a[cursor++]; } see iterator-3a-nested files } } 21 22 Critique Make it Non-Static: Inner Classes • Good: class Shark { – Shark code and remora code in the same file private Comparable[ ] a; // client code • Class is Shark.Remora so compiler knows where to find it. public Iterator makeRemora( ) { return new Remora(); – Users know that Remora is specific to Shark class. Shark s = new Shark(…data…); } – Can now have Dolphin.Remora, Whale.Remora, etc… // let shark make it for us – Data is private again public class Remora // inner class Iteratorr2 = s.makeRemora( ); implements Iterator{ • Bad: int cursor = 0; // make our own Remora – Clients can still create Remoras on their own // same code, but “myShark” is implicit Remora r1 = s.new Remora(); public Remora( ) { } – Each Remora “belongs” to exactly one Shark public Object next( ) { • Java language could enforce this linearSearch(r2, v); return a[cursor++]; – Remora code must keep writing “ myShark.blah” } } • It could be implicit, since everything in Remora refers to the Shark see iterator-3b-inner files } 23 24 4

Recommend


More recommend