380 likes | 394 Views
Learn about arrays in Java programming, how to declare, initialize, and access elements in an array. Understand the importance of arrays when retaining multiple values.
E N D
Arrays for(i=0;i<n;i++) { value = in.nextInt(); sum += value; } double average = (double)sum/n; • Consider the following code which inputs numbers from the user and computes their average • Each time we input a new value from the user, we throw out the old value • What if we need to retain all of the values? • for instance, we might want to know how many of the input numbers are greater than the average • since we throw out all the numbers, and only compute the average at the end, how then can we step through each input number to compare it to the average? • With 1 variable, we can only retain 1 value, we lose all the others • we need a different type of variable that can store multiple values at one time
The Array Type • An Array is a variable type which can store multiple values • we sometimes refer to such a variable as a container • Arrays in Java must be typed and sized • specify the type of value that the array will store • specify the size of the array • Syntax to declare an array • type[] name; • name = new type[size]; • The type will be any of the types we have already seen (int, String, etc) • We can combine the two instructions above to declare and instantiate the variable at one time as in • String[ ] names = new String[100]; • this array, called names, can store up to 100 Strings
What does new Do? • We’ve used new whenever we instantiate objects • Random g = new Random(); • Scanner in = new Scanner(System.in); • The command new does two things • it allocates memory space for the object • the allocated memory comes from a special reserved set of memory for your program called the heap • the heap gives us unnamed memory, we have to reference the location(s) in memory using a reference variable • what we call a pointer in many languages, but a reference in Java • that reference is returned by the new command which we store via an assignment statement • it invokes a method called the class constructor • In the case of an array, new allocates a contiguous block of heap memory whose size equals the size of the array * size of the array’s type • double[ ] foo = new double[10]; • gives us 10 * 8 = 80 bytes (remember a double is 8 bytes)
Accessing into an Array • We rarely use the array as a whole, instead we want to access one element of the array • input a value into the array • output a value from the array • assign a value to the array • use a value in the array • We select the particular array value using an array index using the notation name[index] where index is an int value or variable • in Java, array indices start at 0 (that is, the first array location is at index 0) • if our array stores 100 elements, the last index is 99 • recall the first character of a String was also given an index of 0 • We will often use a for loop to iterate from 0 to n-1 to access every array element, one at a time – see the next slide
Example Program System.out.println(“How many names do you have? ”); int n = in.nextInt(); String[ ] names = new String[n]; for(inti=0;i<n;i++) { System.out.print(“Enter name ” + (i+1) + “: ”); names[i] = in.next(); } System.out.println(“The names you entered are:”); for(inti=0;i<n;i++) System.out.println(names[i]); int count=0; for(inti=0;i<n;i++) count+=names[i].length(); double average = (double)count / n; System.out.println(“The average length of the names is ” + average); count = 0; for(inti=0;i<n;i++) if(names[i].toLowerCase().charAt(0)==‘a’) count++; System.out.println(“There were a total of” + count + “ names starting with ‘a’”);
Using a while Loop to Fill an Array • In the previous example, we asked the user for the number of inputs (which would then be the size of the array) • the user may not know the exact number (imagine that the user has a stack of items to input and doesn’t want to count them) • we can use a while-loop and a sentinel value to control the loop but this requires a few changes to our code String[ ] names = new String[100]; // arbitrary size, hopefully not too small int number = 0; // number of elements currently in the array System.out.print(“Enter first name, ‘quit’ to exit ”); String temp = in.next(); while(!temp.equalsIgnoreCase(“quit”)&&number<100) { names[number] = temp; System.out.print(“Enter next name, ‘quit’ to exit ”); temp = in.next(); } Notice our while loop’s condition is testing both temp and number, why are we testing number < 100?
Initializing and Obtaining the Size of an Array • When we declare an array, we can either instantiate it with new or we can initialize its elements • initialization sets the array size, instantiates it, and fills it with the initial values • Syntax: type[ ] name = { list of values separated by commas }; • examples • int[ ] scores = {95, 88, 98, 77, 60, 90, 85}; // scores is an array of 7 items • Strings[ ] names = {“Frank”, “Fred”, “Fernando”, “Francine”}; • double values = {0.0, 0.0, 0.0, 0.0, 0.0}; • the array’s size is dictated by the list of values and so you lose the flexibility of having an array that has room left over for more values if needed • we address the problem of how to change an array’s size later in this chapter • If you need to know the size of an array, use name.length • this is not a method call, there are no ( ) after length • this returns the size of the array, not the number of elements currently stored there
The foreach Loop • In our examples so far, we have used a for loop to input and iterate through the array and a while loop to input into an array • In later versions of Java, they introduced a new instruction called the foreach loop • if you are familiar with Python, it is like Python’s for loop • rather than counting, it uses a list of values and iterates through each one, one at a time • even though its called the foreach loop, syntactically it uses the word “for” • Syntax: for(typevar : list) statement; • type is the type of value stored in the list • varis the loop variable that you will use to reference each element • list is the variable storing the list • while we will use an array here, you can use other list types available in Java • if varis previously declared, you will omit the type from the statement • as with for loops, if the loop body is more than 1 statement, place them all in { }
Example: Using the foreach Statement Scanner in = new Scanner(System.in); int[] values = new int[100]; intnumber=0, temp, sum = 0, count = 0; System.out.print("Enter positive numbers, 0 to quit "); temp = in.nextInt(); while(temp>0 && number<100) { values[number] = temp; number++; sum+=temp; System.out.print("Enter positive numbers, 0 to quit "); temp = in.nextInt(); } double average = (double)sum/number; for(intnum : values) if(num > average) count++; System.out.println("Of " + number + " values entered, " + count + " are greater than average"); See the example on page 253 for a version using a counting for loop instead of the foreach
Example: Deck of Cards • Here we present a program that will randomly deal cards from a deck of cards into a 5-card hand • the deck will be represented as an array of 52 booleans, called dealt, indicating whether a given card has yet been dealt • the hand will be an int array where each element stores a number from 0 to 51 • we will store the names of the 4 suits in an array of Strings • used when converting the int value (0 to 51) into the name of the card like 5 of Spades • We need to make sure that we do not deal the same card twice • there is nothing in the Random class that would prevent the same number from being randomly generated in a short time span • to generate 5 cards, use a loop like for(inti=0;i<5;i++) • we use a do-while loop and the dealt array as follows • do { generate a number from 52 } while (dealt[number]); • dealt[number] = true; • hand[i] = number;
public static String convert(int c) { c = c % 13 + 2; if(c==14) return "Ace"; else if(c==13) return "King"; else if(c==12) return "Queen"; else if(c==11) return "Jack"; else return ""+c; } Random g = new Random(); boolean[] dealt = new boolean[52]; for(inti=0;i<52;i++) dealt[i] = false; int[] hand = new int[5]; inttemp; String[] suits = {"Clubs", "Diamonds", "Hearts", "Spades"}; for(inti=0;i<5;i++){ do { temp = g.nextInt(52); }while(dealt[temp]); dealt[temp] = true; hand[i] = temp; System.out.println(temp); } System.out.print("Your hand is "); for(intcard : hand) { System.out.print(" " + convert(card) + " of " + suits[card / 13]); } System.out.println();
Copying Arrays • Assume we have the following code • int[] list1, list2; • list1 = new int[…]; • // code that fills list1 • list2 = list1; • Does this copy list1 into list2? • no • Arrays are objects and all objects are pointed to by reference variables • that is, list1 is not the array itself but the memory location of where the array is stored • doing list2 = list1; copies the location of list1 into list2 • therefore list1 and list2 are both pointing at the same array • change list2 now and you are changing list1 • If we truly want a copy of list1 in list2, we have to copy all of the elements, one at a time • list2 = new int[list1.length]; • for(inti=0;i<list.length;i++) list2[i] = list1[i];
Passing an Array as a Parameter • Recall all primitive types of variables are passed to methods by value • a copy of the actual parameter is copied into the formal parameter, changing the value in the formal parameter has no impact on the actual parameter • Arrays are objects, all objects are passed by reference • changing elements in the array in the method changes the array itself If y were an int and not an array, its value is copied into numbers on the stack so that changing numbers in m does not change y in Main Since y is an array, we copy its reference into numbers in the stack so that changing numbers changes y
Example public static void main(String[] args) { int[] x = {1, 2, 5, 10, 20, 100}; intnumber = 6; for(inti=0;i<number;i++) System.out.println(x[i]); change(x, number); for(inti=0;i<number;i++) System.out.println(x[i]); } public static void change(int[] a, int n){ for(inti=0;i<n;i++) a[i]=a[i]+1; } Output: List before changing: 1 2 5 10 20 100 List after changing: 2 3 6 11 21 101 int[] b = new int[a.length]; for(inti=0;i<n;i++) b[i] = a[i]; for(inti=0;i<n;i++) b[i]=b[i]+1; System.out.print("\nList in change: "); for(inti=0;i<n;i++) System.out.print(b[i]+" "); What if you don’t want the array changed? Make a copy of it For instance, we change the change method to be as shown to the right New output: List before changing: 1 2 5 10 20 100 List in change: 2 3 6 11 21 101 List after changing: 1 2 5 10 20 100
Passing Arrays vs Passing Array Elements • One of the things we do with array is sort them • Part of sorting is identifying two elements that need exchanging • we call this a swap • Here, we look at how to swap 2 elements of an array – the right way and the wrong way public static void swap(int x, int y) { int temp = x; x = y; y = temp; } public static void swap2(int[] x, inti) { int temp = x[i]; x[i] = x[i+1]; x[i+1] = temp; } In main: int[] a = {1, 2}; int index = 0; swap(a[0], a[1]); System.out.println(a[0] + “\t” + a[1]); swap2(a, index); System.out.println(a[0] + “\t” + a[1]); Output: 2 // swap did not work as expected 1 // swap did work as expected
Returning an Array from a Method • Arrays can also be returned by a method as the return type • The return type would include [ ] as in • public static int[] getArray(…) • You might want to return an array if you are • inputting an array that didn’t exist prior to invoking the method • creating a copy of an array • manipulating an array but wanting to retain the original String[] list = new String[100]; // … fill list with values String[] list2 = reduceList(list, n); public static String[] reduceList(String[] list, int n) { String[] list2 = new String[n]; int j = 0; for(inti=0;i<n;i++) if(list[i].toLowerCase().tocharAt(0)) == ‘a’) list2[j++] = list1[i]; return list2; }
Example: Reversing the Items in an Array • Imagine that we want to take the elements of an array and reverse their ordering • should we convert the array itself or create a second array? • we look at both solutions here public static void reverse(int[] a, int n) { for(inti=0;i<n/2;i++) { temp = a[i]; a[i] = a[n-i-1]; a[n-i-1] = temp; } } public static int[] reverse2(int[] a, int n) { int[] b = new int[n]; for(inti=0;i<n;i++) b[i] = a[n-i-1]; return b; } We call the first method using reverse(array, n); We call the second method using int[] array2 = new int[array.length]; array2 = reverse2(array, n);
Counting Letters • Write a program which counts the number of occurrences of each letter and the starting letter of each word found in a String • we will need 2 arrays, the occurrence for each of the 26 letters (we will ignore case, and ignore non-letters) and the occurrence of times a letter starts a word for each of the 26 letters • we iterate through the array looking at every letter (we will ignore non-letters such as spaces) • we have to convert the letter into an array index (‘a’ becomes 0, ‘b’ becomes 1, etc) int[] firstLetters = new int[26], allLetters= new int[26]; char c; inttemp; for(inti=0;i<26;i++) firstLetters[i] = allLetters[i] = 0; for(inti=0;i<someString.length();i++) { c = someString.toLowerCase().charAt(i); if(c>='a'&&c<='z') { temp = (int)c - 97; allLetters[temp]++; if(i>0&&someString.charAt(i-1)==' ') firstLetters[temp]++; } }
What does String[] args Mean? • We’ve seen this in every program in our main method’s header • What does it mean? • we now know what String[] is: an array of Strings • what is args? the name of a parameter • Although we are running Java from an IDE, we can, once compiled, run our Java programs from a command line (such as if you are running a Linux/Unix OS) • Let’s say we have a program called foo • We can run it, once compiled, as foo param1 param2 param3 • The parameters are wrapped up and placed into an array of Strings • in our program, foo, we could reference these as args[0], args[1], args[2] • this allows us some flexibility in that we can provide input into our program without using a Scanner – all of the input is brought in at one time though, there’s no interaction (this is sometimes called batch processing)
Example • Let’s assume that the program will receive a list of integer numbers • Our program will sum them up and output the result • since the list of parameters is being brought in and stored in a String array, we will have to access each String and convert it to a number • you might recall we can do this with Integer.parseInt(String) • note that if the user enters a non-String in the list, we will get a run-time Exception causing the program to terminate public class CommandLineSummation { public static void main(String[] args) { int sum = 0; for(inti=0;i<args.length;i++) sum+=Integer.parseInt(args[i]); System.out.println(“The sum of your input parameters is ” + sum); } } We could also use for(String s : args) sum+=Integer.parseInt(s); If called as CommandLineSummation 5 10 4 16 3 the output will be The sum of your input parameters is 38
Searching an Array: Part 1 • We will want to search an array for many reasons • looking for a specific value to see if it is there • looking for a specific value to know where it is stored • looking for a value that fulfills a category • e.g., the largest value in the array • looking for all values that fulfill a category • e.g., all values that start with an ‘a’ • In the first two cases, we search until we either find the value or reach the end of the array – this is known as a sequential search • if the array is sorted, we can use the binary search (much more efficient) • In the last two cases, we search the entire array • looking for the largest value requires remembering the largest value so far to compare against the remaining elements • let’s explore these search strategies
Searching on Criteria • To find all elements that fulfill a certain criteria • for loop to iterate through each element of the array • if statement to test if this element fulfills the category • if so, output it or add 1 to a counter • example: all Strings that start with the letter ‘a’ • for(String s : list) • if(s.toLowerCase().charAt(0)==‘a’) counter++; • To find the largest value • start maximum off to an initial value but make sure it is not larger than any value in the array – you might start it off as the first value in the array • int max = array[0]; • for loop to iterate through the entire array, comparing each element to max • for(int temp : array) • if(temp > max) max = temp;
Sequential Search • Search for the value in key in the array, marking the index where we find key in the variable location (-1 means we didn’t find key) key = 3 location = -1 index = 0 index = 1 index = 2 index = 3 index = 4 index = 5 location = 5 Iterate through the array until you find key or reach the end of the array Use a for loop with an if statement
Example public static int search(int[] array, int n, int key) { int location = -1; // initialize to -1 assuming we won’t find it for(inti=0;i<n&&location==-1;i++) if(array[i]==key) location=i; return location; } In main: … int location = search(a, n, k); if(location==-1) System.out.println(k + “ was not found”); else System.out.println(k + “ was found at ” + location); Notice how the for loop searches until either it reaches the end of the array (i==n) or has found key in the array Let’s imagine we are looking for a value in an array of 10 elements, in the worst case it would take 10 searches to find the item (if its in the last position) or that it wasn’t there – this search approach seems reasonable, but what if there were 10 million items in the array? Not so efficient, is it?
Binary Search • Ever look through a phone book or a dictionary? • Do you start on the first page to find something? Not usually • where do you start looking? maybe in the middle? why? • Imagine that you look in the middle and discover that this is not the item you are looking for • where do you look now? well, because the items in a dictionary or phone book are in sorted order, by looking right in the middle you have narrowed down your search to half of the book • if the item you find in the middle is greater than the item you are looking for, you now just have to search the first half of the book, and if its less than, then just the second half of the book • what now? do the same thing with the half of the book you have remaining • look at the middle of the half that’s remaining • in looking at 1 item, you’ve narrowed it down to ½, in looking at a second item, you’ve narrowed it down to ¼, in looking at a third item, you’ve narrowed it down to 1/8, etc
Binary Search Illustrated We will keep track of 3 items: low – the lowest index yet to search high – the highest index yet to search mid = (low + high) / 2 if(array[mid] > key) search lower half by resetting high = mid – 1 else search upper half by resetting low = mid + 1
Implementing Binary Search public static intbinSearch(int[] array, int n, int key) { int low = 0, high = n-1, mid; while(high>=low) { // haven’t found key and still have room to search mid = (low + high) / 2; // compute new mid point if(array[mid]==key) return mid; // found item, return its location else if(array[mid] > key) // narrow down to the upper half high = mid - 1; else low = mid + 1; // narrow down to the lower half } return -1; // if we reach here, high became < low and we never found key, } // so return -1 Example: array = 1 4 6 10 15 16 22 n = 7 key = 15 low = 0, high = 7, mid = (0+7)/2 = 3 array[mid] < key, reset low = mid + 1 = 4 low = 4, high = 7, mid = (4+7)/2 = 5 array[mid] > key, reset high = mid – 1 = 4 low = 4, high = 4, mid = (4+4)/2 = 4 array[mid] == key, return mid (4) Try to search for key = 17
Computational Complexity and Search • We can prove that binary search is better than sequential search using a computational tool known as complexity analysis • We will do this informally • in sequential search, if an item is not in the array or is at the end of the array, it will take n loop iterations to determine this where n is the size of the array • we refer to such a complex as O(n) (order n) • 1000 items can take as many as 1000 searches, 1 million items can take as many as 1 million searches • for binary search, we saw that after 1 search, our search space has been halved, after each additional search, the remaining space is halved • after 1 iteration 1/2 (1 / 21) • after 2 iterations 1/4 (1 / 22) • after 3 iterations 1/8 (1 / 23) • … • after n iterations 1/2n • If there are n items to search, we reach low = high = mid after log 2 n searches so we either have found the item or have a situation where high < low after log 2 n searches
Comparing log 2 n to n • We refer to the complexity of binary search as O(log n) • as n increases, the amount of search required increases logarithmically • you can see that a sequential search of an array of 1 million items will take roughly 1 million iterations whereas for binary search it will take no more than 20 • We want to sort our arrays if we are going to be searching them for specific key values to improve our search performance • Note when searching for a criterion (such as counting the number of even numbers in a list) will not be impacted by sorted or unsorted arrays because we still have to look at all of the elements – so a criteria based search is O(n)
Sorting • So that leads us to the next topic: how do we sort the elements in an array? • Just as we saw that there are two ways to search for an item in a list (sequential vs binary), there are numerous ways to sort a list • Some are more efficient than others, some are easier algorithms to understand and implement than others • for 260, we will consider 3 sorting algorithms and implement two of them • but there are many sorting algorithms and you learn others in 360 and 364 • We will discuss selection sort, insertion sort and bubble sort • Let’s start with selection sort: • for each array i from 0 to n – 2 do the following • find the smallest value between i and n – 1 • swap that element with the element at location i
Selection Sort Code and Why It Works public static void ssort(int[] a, int n) { int min, minIndex, temp; for(inti=0;i<n-1;i++) { min = a[i]; minIndex = i; for(int j=i+1;j<n;j++) if(a[j]<min) { min = a[j]; minIndex = j; } } temp = a[i]; a[i] = a[minIndex]; a[minIndex] = temp; } } The outer loop makes one pass down the array For each pass, the inner loop looks from the current value on looking for the smallest value and swapping it with the current value Because we are using 2 nested for loops, the complexity of this code is O(n2)
Insertion Sort • Imagine that you have a set of index cards with names on them and you want to sort them • compare the first two cards and order them (you’ve compared 2 cards) • take the 3rd card and compare it to the 1st card, if 3rd < 1st, insert at beginning and you are done otherwise compare against 2nd and insert 3rd card before or after 2nd • take the 4th card and compare it to the 1st inserting it before the 1st if 4th < 1st, else compare against 2nd, insert before 2nd if 4th < 2nd else compare against 3rd and insert before or after 3rd • Notice how the number of cards you compare against grows with each new card • in the worst case, you are comparing the 2nd card against 1 card, the 3rd card against 2 cards, the 4th card against 3 cards, etc, or in the worst case you have the following number of comparisons • 1 + 2 + 3 + 4 + … + n – 1 = n * (n – 1) / 2 which is approximately n2/2 • this sort gives us a complexity of O(n2) like selection sort • but in the best case, you compare the next card only against the first card, for instance if the list is in sorted descending order, then each new card is always going to be inserted at the beginning of the list giving you the following number of comparisons • 1 + 1 + 1 + … + 1 = n-1 total comparison, or O(n)!
int temp; for(inti=1;i<n;i++) { temp = array[i]; for(int k=i-1;k>=0&&array[k]>temp;k--) array[k+1] = array[k]; array[k+1] = temp;
Bubble Sort • The idea behind the bubble sort is to let the largest values “bubble” their way up the array • we do this by making continual passes across the entire array, comparing two adjacent values and swapping them if needed • For instance, imagine our array is: 5 2 6 3 4 • first pass: 5 vs 2, swap them: 2 5 6 3 4, 5 vs 6, do not swap them, 6 vs 3, swap them: 2 5 3 6 4, 6 vs 4, swap them: 2 5 3 4 6 • notice how the largest value bubbled up to the top while we also have somewhat arranged the rest of the numbers • since the array is not yet sorted, we continue • second pass: 2 vs 5, do not swap them, 5 vs 3, swap them: 2 3 5 4 6, 5 vs 4, swap them: 2 3 4 5 6 • we do not need to look at 5 vs 6 because we know 6, being the largest, has bubbled to the end of the array • the array is now sorted, but the way the algorithm works is that since we swapped values, we check again – once we make a complete pass without swapping elements, we are done • third pass: 2 vs 3, do not swap, 3 vs 4, do not swap, we know 5 and 6 are in the right place, done, no swapping so the array is now sorted
Bubble Sort Implemented booleansorted = false; while(!sorted) { // continue to loop until we make no swaps in an entire pass sorted = true; // assume this will be our last pass for(inti=0;i<n-1;i++){ // iterate down the pass up to n-1 (which shrinks) if(a[i]>a[i+1]){ // if the current value > next, swap them temp=a[i]; a[i]=a[i+1]; a[i+1]=temp; sorted = false; // since we swapped something, array not currently sorted } } n--; // for next pass, largest value already sorted, reduce pass length } • n is initialized to the size of the array • Notice that the while loop has to iterate at least one time BUT will iterate only one time if the array is already sorted • so in the best case, this sort algorithm is O(n) • At worst, it will iterate n times giving a complexity of O(n2)
The Arrays Class • Like Math, there is an Arrays class (part of java.util, you need to import it) • Among its methods is a sort method that will sort an array that you pass to it • Example • int[] array = {6, 3, 2, 8, 4, 7, 5}; • Arrays.sort(array); • this method has optional parameters of the starting index and the index after the ending location that you want sorted, without these two indices they default to sorting the entire array • The Arrays class has other useful methods, here are a couple • binarySearch(array, value) – returns the index of value if found and a negative value (not necessarily -1) if it is not found • equals(array1, array2) – returns true if the values in the two arrays are exactly the same, false otherwise • fill(array, value) – fills the entire array with value, you can add parameters to limit which elements are filled using fill(array, startIndex, endIndex, value) • remember to use any of these, you must include Arrays. before the method
Array Doubling • When you instantiate an array, you must specify its size • what if the size you specify is too small? can you grow the array? • no, but you can create another array which is larger and the move the elements from the old to the new • we call this array doubling because you usually create a new array twice the size of the old • The problem with array doubling is that it is not efficient • if our array started with 10 elements, doubling requires that we copy all 10 elements into the array, of size 20 • the next time we double, we have to copy 20 elements, twice as many as last time • the next time we are up to 40 elements, etc so we have now copied 70 items, had we started with an array of 80, we wouldn’t have had to copy anything int[] array = new int[10]; int n = 10; // fill array here n *= 2; int[] array2 = new int[n]; // copy elements of array into array2 array = array2
Common Errors and Pitfalls • Iterating through an array using indices 1 to n instead of 0 to n-1 • if an array has n elements, then array[n] is a SubscriptOutOfRangeException • we refer to errors like this as “off by 1 errors” • Confusing the Python list/tuple with the Java array • in Java, all array elements must be the same type • Forgetting to instantiate the array • int[] array; • array[0] = …; // this is an error • Forgetting that arrays, being objects, are passed by reference and so manipulating the array in a method alters the original array • Trying to copy an array using array2 = array1; • remember that this causes both variables to point at the same array in memory so you are not creating a copy, merely referencing the one array with two different variables • Using sequential search on a sorted array – if its sorted, use binary search for efficiency!