440 likes | 597 Vues
COP 3540 Data Structures with OOP. Arrays Chapter 2. The Basics of Arrays in Java – Array Creation. Two kinds of Arrays: primitive (ints, floats, double, char, unsigned, …) and objects In Java arrays are objects not primitives.
E N D
COP 3540 Data Structures with OOP Arrays Chapter 2
The Basics of Arrays in Java – Array Creation • Two kinds of Arrays: • primitive (ints, floats, double, char, unsigned, …) and • objects • In Java arrays are objects not primitives. • Since all arrays are objects, must use ‘new’ to create. • Two ways to create an array in Java • 1. int[ ] intArray; // only the reference intArray = new int[100]; // creates the array with space for 100 integers // intArray now points (references) this array. 2. Alternatively: int intArray[ ] = new int[100]; Either format is acceptable. (I prefer the latter) What is a primitive? Where is the array data actually stored? Where is the reference stored? Attribute: int arrayLength = intArray.length; // number of elements • Where does this ‘length’ attributecome from? • How do you know intArray.length is not a method?
The Basics of Arrays in Java – Accessing Array Elements • Array access is via an index number What is an index? Same as a subscript? temp = intArray[3]; //assign value of fourth element // in intArray to temp (assumes // temp is an int). intArray[7] = 66; // assigns value of 66 to // intArray[7]. (8th element) Array Index Out of Bounds – discuss…. intArray = new int [100]; // bounds?
The Basics of Arrays in Java – Initialization • Unlike other languages, integer arrays are set to 0. • autoData[ ] carArray = new autoData[4000]; • “I have an array of autoData objects named carArray and have 4000 of them.” • Each array element has null value (pointer value is null) • No object values have been created. • Assigning values to primitive array types: • int[ ] intArray = {2,4,78,54,67}; // initializationlist • Also sets array to five elements: intArray[0] … inArray[4].
The Basics of Arrays in Java – Array Example – p1 // array.java - // demonstrates Java arrays This is an array of primitives / not objects!! class ArrayApp { public static void main(String[] args) { long[ ] arr; // reference to array // what is a ‘long?’ arr = new long[100]; // allocates array for 100 ‘longs.’ // ‘long’ is a primitive or object? int nElems = 0; // number of items (to be used for size of arr) int j; // loop counter long searchKey; // key of item to search for //-------------------------------------------------------------- arr[0] = 77; // insert 10 items // brute force approach!! arr[1] = 99; // specifically assigning each element to arr[2] = 44; // a specific location in the array! arr[3] = 55; arr[4] = 22; //’hard coded values” arr[5] = 88; arr[6] = 11; arr[7] = 00; arr[8] = 66; arr[9] = 33; nElems = 10; // now 10 items in array //-------------------------------------------------------------- for (j=0; j< nElems; j++) // display items // value of j upon leaving loop? System.out.print( arr[j] + " "); // How many times is the ‘for’ executed? System.out.println (""); // How many time is the System.out… executed //--------------------------------------------------------------
The Basics of Arrays in Java – Array Example – p2 // Continuing… searchKey = 66; // find item with key 66 for(j=0; j<nElems; j++) // for each element, // any difference here j++ or ++j ?? if(arr[j] == searchKey) // found item? break; // yes, exit before end // What does ‘break’ do? if(j == nElems) // at the end? System.out.println("Can't find " + searchKey); // yes Will this always work??? else System.out.println("Found " + searchKey); //-------------------------------------------------------------- searchKey = 55; // delete item with key 55 for(j=0; j<nElems; j++) // look for it if(arr[j] == searchKey) break; for(int k=j; k<nElems; k++) // move higher ones down // what if k = nElems? Will this work? arr[k] = arr[k+1]; nElems--; // decrement size // check: either we get a hit or not. Check both! // What is wrong with this little routine? //-------------------------------------------------------------- for(j=0; j<nElems; j++) // display items System.out.print( arr[j] + " "); System.out.println(""); } // end main() } // end class ArrayApp Note: all processing is in one single method, main!
Program Organization • Program looks like a COBOL program or a C program. • All components: data and procedure – are smushed together. • No chance for reuse; extension; information hiding, etc. • Will it work? Yes. But it does NOT take any advantage of OO features. • In general, this is poor programming…
Dividing the Program into Classes • To build a much better program that is easier to maintain, reuse, and understand, separate the data from its clients. • Develop a class that contains the data itself and the methods that access / manipulate that data. • Encapsulation • Information hiding • Protect the data and control access.
Better Approach: the lowArray.java Program Here is the class (object) with its data declarations and methods for accessing that data. All ‘clients’ may have access to the array, a, via the methods in LowArray objects. Access to objects of type LowArray are NOT tied to a specific implementation! // lowArray.java // demonstrates array class with low-level interface //////////////////////////////////////////////////////////////// class LowArray { private long[ ] a; // ref to array a //note ‘private’ //-------------------------------------------------------------- public LowArray(int size) // constructor// note public methods { a = new long[size]; } // creates array of a size ‘passed’ to it! //-------------------------------------------------------------- public void setElem(int index, long value) // set value { a[index] = value; } // sets a specific element value. //-------------------------------------------------------------- public long getElem(int index) // get value { return a[index]; } // ‘gets’ a specific element and //-------------------------------------------------------------- // returns value to client. } // end class LowArray //////////////////////////////////////////////////////////////// Note how nicely these work together! What kind of variables are: index, value, and a? What are their visibilities?
class LowArrayApp { public static void main(String[] args) { LowArray arr; // reference to an object of type LowArray. arr = new LowArray(100); // create LowArray object and passes 100 as argument for number of elements int nElems = 0; // number of items in array int j; // loop variable arr.setElem(0, 77); arr.setElem(1, 99); arr.setElem(2, 44); arr.setElem(3, 55); arr.setElem(4, 22); // do NOT DO THIS!!! arr.setElem(5, 88); arr.setElem(6, 11); arr.setElem(7, 00); arr.setElem(8, 66); arr.setElem(9, 33); // DONE ONLY FOR SPACE.. nElems = 10; // now 10 items in array // --------------------------------------------------------------------------------------- for(j=0; j<nElems; j++) // display items System.out.print(arr.getElem[j] + " "); System.out.println(""); // --------------------------------------------------------------------------------------- int searchKey = 26; // search for data item for(j=0; j<nElems; j++) // for each element, if(arr.getElem[j] == searchKey) // found item? break; if(j == nElems) // nope System.out.println("Can't find " + searchKey); else // yes System.out.println("Found " + searchKey); // ---------------------------------------------------------------------------------------- for(j=0; j<nElems; j++) // delete value 55 if(arr.getElem[j] == 55) break; for(int k=j; k<nElems; k++) // move ‘higher’ ones down arr.setElem(k, arr.getElem(k+1) ); nElems--; // decrement size // ---------------------------------------------------------------------------------------- for(j=0; j<nElems; j++) // display items System.out.print( arr.getElem(j) + " "); System.out.println(""); } // end main() } // end class LowArrayApp
Evaluation? • What do you think? • Advantages? • Other than separating data from user, not too much! • Data separated from user (clients) Good. • Data is private and only LowArray class methods have access to the data. Good. • Requires other clients (users) to use objects. Good. • Classes have clearly defined roles. Good • LowArray class is called a Container Class • Container Classes store data and provide methods to accessing and manipulating elements in it. • Still, not so hot!!
First: A little bit on Class Interfaces • What is: System.out.println (“Hello there!”); • Is this statement like a: • Write printrec from detailrec in COBOL? • Is it like: printf (“Hello there!\n”); in C ?? • What is it???? • How do things ‘work’ in the OO paradigm??
Discussion: pg. 1 of 2 (We’ve already talked about these, but…) • Classes have … ‘responsibilities;’ objects of a class provide services’ (i.e, they ‘do’ things! • What does this mean? • Classes (really, ‘objects’ of a class) may have many / varied users who wish different services provided to them. • Compute gpa; print name and SSAN, etc. • If the class is a high-usage class, it should be designed to provide flexibility for its clients. • Services (the methods) are ‘provided’ via the class interface: the methods and their ‘signatures.’ • The ‘whats’ are provided and ‘how’ to get them.
Discussion: pg 2 of 2. • Consider LowArray class. • Its ‘public interface’ (i.e., the signatures of its public methods) are among the most basic of services • ‘Creating’ ‘getting’ and ‘setting’ are extremely primitive services…. • Chances are users of this data will still have to do most of the manipulation themselves in this scenario! • Not much real valuable ‘service’ provided. • Separating data from its users is a step forward. But we can do much better! • Consider the highArray.java program. (next slides) • First: look at the Container class, HighArray • Secondly, look at the app(lication) that uses the services of objects of type HighArrayApp
class HighArray { // have taken some spacing liberties to fit this on one page… private long[] a; // ref to array a private int nElems; // number of data items public HighArray(int max) // constructor { a = new long [max]; // create the array nElems = 0; // no items yet } // end Constructor- public boolean find (long searchKey) { // find specified value int j; for (j=0; j<nElems; j++) // for each element, // /note that the class provides the search capability! Nice ‘service.’ if (a[j] == searchKey) // found item? // Client does not have to be concerned over ‘how’ the search isundertaken! break; // exit loop before end // Search was done in the app last time and NOT in the object….. This is MUCH better. if(j == nElems) // gone to end? return false; // yes, can't find it else return true; // no, found it } // end find() //----------------------------------------------------------- public void insert(long value) // put element into array { //note the services provided by the object a[nElems] = value; // insert it // note the public interface. nElems++; // increment size // Note that the object controls all indexing, looping, etc!! } //----------------------------------------------------------- public boolean delete(long value) { // Again, note the service: delete is accommodated within object! int j; // Client just requests a simple ‘delete’ service! for(j=0; j<nElems; j++) // look for it if( value == a[j] ) // Client really doesn’t care about ‘how’ the delete is done. break; // only that it IS done. if(j==nElems) // can't find it return false; else // found it { for(int k=j; k<nElems; k++) // move higher ones down a[k] = a[k+1]; nElems--; // decrement size return true; } } // end delete() //----------------------------------------------------------- public void display() // displays array contents { for(int j=0; j<nElems; j++) // for each element, System.out.print(a[j] + " "); // display it System.out.println(""); }// end display() } // end class HighArray
Infinitely better!!! Let the object do the work for client! class HighArrayApp Here’s the Application! { public static void main(String[] args) { int maxSize = 100; // array size HighArray arr; // creates a reference to an object. arr = new HighArray(maxSize); // creates object arr and passes 100 to its constructor. arr.insert(77); // insert 10 items Note: we only supply value not arr.insert(99); // it’s the job of the object to insert the element into the array. arr.insert(44); // We have sent a message to arr to provide this service to us. arr.insert(55); arr.insert(22); Note: we don’t handle indices arr.insert(88); Note: we don’t loop arr.insert(11); Note: we don’t controlthe type of search!!!! arr.insert(00); arr.insert(66); arr.insert(33); arr.display(); // displayitemsWe simply requestl the object to provide those services!! (assuming it can via its public interface that is,assumingit is well-designed for its clients). int searchKey = 35; // search for item if( arr.find(searchKey) ) System.out.println("Found " + searchKey); else Still more: give parameter and request Search! No more! System.out.println("Can't find " + searchKey); We are ‘abstracting out’ the details of these operations!! Let the object that has responsibility for the data arr.delete(00); // delete 3 itemsdo the searching, manipulating, etc. arr.delete(55); Let client (HighArrayApp) merely request this service! arr.delete(99); arr.display(); // display items again } // end main() } // end class HighArrayApp // Note how short main (driver) really is. It drives the app.
Ordered Arrays • Will use an OrdArray class to encapsulate the array itself (data) and its methods (algorithms). • Most essential part of this example is, of course, the ‘find’ algorithm, which uses a binary search to find / not-find a specific item. • Let’s look at the method first.
Binary Search with the find() Method Let’s look at the find() routine… public int find (long searchKey) { int lowerBound = 0; int upperBound = nElems-1; int curIn; // ‘curIn’ = current index while (true) { curIn = (lowerBound + upperBound) / 2; //set curIn to middle of range. if (a[curIn] == searchKey) return curIn; // found target, Great! else if (lowerBound > upperBound) return nElems; // can’t find it. End of routine. else // adjust bounds of ‘array.’ { if (a[curIn] < searchKey) lowerBound = curIn+1; // look in upper half else upperBound = curIn – 1; // look in lower half } // end else divide range } // end while } // end find() Scope terminators GO THROUGH THE ALGORITHM. CAN YOU GO THROUGH IT?? Go through – try the ‘hit’ being at position 57 in the array…
Assumes desired element is in location 57… Range: 0 + 99 = 99 / 2 = 49.5 curIn = 49 (size of array = 100) Hit? No. ‘not found?’ NO. a[curIn] < searchKey? Yes. (if target is in array, it is in upper half) lowerBound = curIn+1; iterate Range: 50 + 99 = 149 / 2 = 74.5 curIn = 74 (size of array = 50) Hit? No. ‘not found?’ No. a[curIn] < searchKey? No. (if present, target is in lower half) upperBound = curIn – 1; 74-1 = 73; iterate Range: 50+73 = 123 / 2 = 63.5 curIn = 63 (size of array is 24) Hit ? No., Not Found? No a[curIn] < searchKey? No (if present, target is in lower half) upperBound = curIn – 1; 63 – 1 = 62; iterate Range: 50 + 62 = 112 / 2 = 56. curIn = 56. (size of array is 13) Hit? No. Not found? No a[curIn] < searchKey? Yes (if present, target is in upper half) lowerBound = curIn + 1; 56 + 1 = 57 iterate Range: 57 + 62 = 119 / 2 = 59.2 curIn = 59 (size of array is 6) Hit? No. Not Found? No a[curIn] < searchKey? No. (is in lower half) upperBound = curIn – 1 59 – 1 = 58. Range: 57 + 58 = 115 / 2 = 57.5 = 57. (size of array is 2) Hit? Yes. Number of ‘probes’ = 6. Remember this. Number of probes refers to number of ‘compares.’ “Do I have a hit here?” counts as one probe…
More on Ordered Arrays (1 of 2) • Disadvantages: • Insert() – horribly long. • If new item to be inserted belongs in a lower position of array, movement of data items to ‘insert’ in place can be horrific! • Delete() – horribly long in BOTH ordered and unordered because element to be deleted must be: • First: found, (easier, if item is in ordered array) • Then, remaining elements must be moved to cover up the deleted element’s location.
More on Ordered Arrays (2 of 2) • Advantages: • If array is of sufficient sizeAND is ordered, search times are much faster than with linear searches. • Ordered arrays – super when look-ups (that is ‘searches’) are frequent and array is of sufficient size. • But in ordered arrays – adds/deletes are terrible. • But if maintenance (insertions, deletions) is not done a lot, then this may be the best deal!) • Good examples: • Database of company employees and similar applications when adds and deletes are few. (May batch up adds and deletes and run overnight or off-line) • Large Tax tables – relative stable. Inventories, Large / long lists of all kinds that are not updated very frequently.
Searching • For a sequential search with ‘small n’, search times can be very quick due to computation of index and access…merely add one. • As ‘n’ (size of array) increases, however, (assuming data is ordered) the performance is significant. • Example: • N = 20 • Sequential search: average number of probes: 10 • Binary search: maximum number of probes 5 • 5? How so? 25 = 32 (next integer power of 2 > array size…) • But don’t be misled. We must consider overall performance. This may not be a significant difference in performance (time). More ahead. • KNOW INTEGER POWERS OF 2 UP TO 212 • There is no free lunch!!! • To search an array using a binary search, the array MUST BE ORDERED! (SORTED) and this may require processing overhead! (sometimes a lot!) But, then again, if array is reasonably stable (contents doesn’t change much), this may be tolerable. • If not sorted, can not undertake a binary search.
Recall:: Linear (sequential) search Binary Search n n Search times for two search algorithms and their ‘cross over’ point
Binary Search Performance • So, what does all this mean? • These are easy to understand and essential to know. • Consider the table size discussion in book: Binary Search Table Size ComparisonsNeeded 10 4 100 7 1000 10 10,000 14 1,000,000,000 30 Please note that given ‘table’ sizes (on the left), the values on the right represent maximum number of probes to find / not-find. (Next integer power of 2 higher than table size.)
Sequential (Linear) Search performance • Sequential (Linear) Search Average Nbr:Maximum Number Table SizeComparisonsNeeded 10 5 10 100 50 100 1000 500 1000 10,000 5000 10,000 etc. Potentially, every element might need to be looked at! Average number of probes ‘to find’ would be half the size of the structure, such as 5, 50, 500 … assuming elements are equally-likely to be anywhere in the array… Maximum number of probes ‘to find’ is the table size!
To start with: You mustknow ‘some’ integer powers of 2! • 2**0 = 1 • 2**1 = 2 • 2**2 = 4 • 2**3 = 8 • 2**4 = 16 • 2**5 = 32 • 2**6 = 64 • 2**7 = 128 • 2**8 = 256 • 2**9 = 512 • 2**10 = 1024 • 2**11 = 2048 • 2**12 = 4096 • 2**13 = 8192 • 2**14 = 16384 • 2**15 = 32768 • 2**16 = 65536 As unreasonable as this might appear to, perhaps, a few of you, you need to be able to come up with these without a calculator. They are basic!!! Equations log2r = s Is equivalent to: r = 2s which I might write: r = 2**s So, 1024 = 2**10 And log21024 = 10 (2 raised to what power = 1024? 10) Write relationship as a logarithm or as integer power of 2.
Equations log2r = s r = 2s In text: given the ‘range,’ how many comparisons are needed to complete the search, s? • Equivalently, given an ‘r’ (table or list ‘size’), we want an equation that gives us ‘s,’ that is, what is the maximum number of probes it will take to ‘find’ or ‘not find’ an element in a list. • So, r = 2s may be 1024 = 2**10 So, the inverse of raising something 2 to a power is a logarithm of base 2: namely s = log2(r) • And log21024 = x or 2x = 1024 (Here, x=10) • Can say: 2 raised to what power = 1024? • Unlikely to exactly have 1024 elements in target. So if table were of size 1000, no more than 2**10 (next higher integer power of two) would be required.
Insertions into an Unordered Array = Constant • This is an easy one. • Unordered array can only be searched sequentially. • Insert algorithm does NOT depend on array size. • Item is merely placed in next available slot. • Same amount of time is always required, regardless of size. • To insert: merely add the element to the end of the array. • Thus, the time is a constant, K. • So, T = K. • K is important and is used as a multiplier to account for the speed of • the processor, and • other hardware features.
Insertions into an Ordered Array = Terrible • Recall, insertions into an ordered array requires that all of the items be ‘moved up’ to provide room for the new entry to maintain the ‘order.’ • Performance is impacted by size, of course and other factors influence the decision to proceed this way… size of array frequency of insertions / deletions ...
Linear Search: Unordered Array: Proportional to n • Comparisons…. • Sequential search, unordered list, average number of probes will be n/2. • Finding the desired element is ‘equally likely’ to be found early or late in the list. T (time) will on average be n/2. • But we factor in the hardware, and we note that • Time is proportional to a constant k (from the hardware) times the average number of probes anticipated, that is: • T α k * n/2 (time on one machine will not equal time on another…) • K and 2 are usually not nearly as much of a contributing factor to performance as the size of the array, N. Thus they are often ‘ignored.’ • (K is usually quite small and then we take ‘half’ of that, so….) • We simply say: • T = K*N or simply, T α n; i.e, time is proportional to size of array. • Say: average linear search times are proportional to the sizeofarray. • Array twice as large as another one will normally require twice as long.
Binary Search: Ordered Array: Proportionalto log2n • For binary search, our formula for search times is t = k*log 2 (n). Time, T, is ‘proportional’ to the log base 2 of n where n = the number of elements in the search space. ‘Means’ as n increases, time increases proportionally to base 2 of n (not linearly) K is again a constant related to the hardware and is small (and negligible) So, we say: T α k*log2(n) Or simply T α log2n, or Time is proportional to log base 2 of n.
Recall:: Linear (sequential) search Binary Search n n Search times for two search algorithms and their ‘cross over’ point
Big O Notation We need a shorthand way to indicate performance differences (efficiency) of algorithms that search, sort, etc. Enter the ‘Big O’ Notation!
Big O Notation • We’d ‘like’ to say things like, • Algorithm A is twice as fast as Algorithm B. • Can’t always say this. • Performance depends on MANY factors and not just • number of items (n) or • the initial arrangement of items (order). • Even this is not enough. • Performance is often based on the ‘degree’ of un-sortedness… • Generally, however, the factor mostsignificant in determining overall performance is the size, n.
Bottom Lines – Big O Notation • Big O Notation is read “Order of” is used to indicate relative efficiencies. • Linear Search is said to be an O(n) search: • Read, ‘Order n’ search. • This says search time is directlyproportional to the number of elements being searched. • Think sequential search of an integer array. • Binary Search is an O (log2 n) search. • Says binary search time is proportional to log base 2 n. • Think: binary search of an ordered array.
Run Times using Big O – Know this Table Algorithm Running Time in Big O Linear Search (is proportional to) O(n) Binary Search “ O(log2 n) Insertion – unordered array “ O(1) (‘immediate’) Insertion – ordered array “ O(n) Deletion – unordered array “ O(n) must ‘find’ and create space! Deletion – ordered array “ O(n) Says that deletions require an amount of time proportional to the array size.
Additional Relationships using Big O Notation Subjective rating of Big O Values: O(1) is excellent; O(log2 n) is very good in many cases; O(n) is fair; O(n**2) is poor. (have not discussed) There are others too! But things are not quite this simple….and ‘poor’ in some cases is excellent in other cases Remember, these are only guidelines at best and indicate (sometimes) relative performance!
Arrays for the World – Advantages and Disadvantages Unordered Arrays: • A: insertions quick O(1) • D: search times can be quite slow O(n) especially for large arrays. But if small n?? • D: deletions very slow also (find and compress space) O(n) Ordered Array: (assumes array is sorted) • A: search times very quick (O(log2 n)) (if sufficient size) • D: insertion times: O(n) – equally slow as unordered. • D: deletions: very slow also (find and compress space) O(n)
Better Choices in Different Circumstances • O(1) time would be super for many things. • But often not possible… • If not, how about O(log2n)? • Very nice, but no free lunch! (data must be sorted; packed; and algorithm is not trivial.) • Data may naturally exist in a sorted order; perhaps not! • How about using ‘arrays’ in general? • Well, arrays are fixed in size. • Must guess array size from the get-go. Not great! • Other data structures are MUCH more flexible for increasing / decreasing size and provide good performance! • Check out the Vector class! (do this!)
StoringObjects • Primitives: In real world, we normally store many primitives together so we can retrieve them at one time. • Objects: Storing objects is different: • For OO-applications, only the variables (attributes) for an object have separate storage. • The methods are only stored one time.