More on Arrays

Example:
String[] words = new String[8];
words[0] = words[0].trim();

What happens when we run this code?

Null Pointer Mistake

Question: How can we fix the problem in our last example?

String[] words = new String[8];
for(int i = 0; i < words.length; i++)
{
words[i] = "  String " + (i+1);
}
words[0] = words[0].trim();  // no problem now

Searching Arrays for a Value

Searching - locating a particular value (the key) in an array

First Search Algorithm: Linear Search
(Also known as Sequential Search)

• works well for small arrays or unsorted arrays (a sorted array is an array whose entries are in increasing or decreasing order)
• looks at each array entry, starting with first, until either:
• search key is found (and it's index is returned)
• end of array reached (negative integer, say -1, returned)

Code for linear search, for an int array:

public int linearSearch(int[] array, int key)
{
//return key's index in array, or -1 if key does not appear
for(int i = 0; i < array.length; i++)
{
if(array[i] == key) return i;
}
return -1;
}

Algorithm Analysis for Linear Search

If the array elements are unsorted, on average the linear search algorithm will compare the key to half the array elements.

For an array of size n: n/2 comparisons in average case.

How many comparisons in the best case? Worst case?

Second Search Algorithm: Binary Search

• requires a sorted array - algorithm fails on unsorted arrays
• eliminates half of remaining array entries from consideration after each comparison
• compares the middle of the remaining array elements to search key on each pass
• if they are equal, return index
• if not, and search key < middle array element, search first half of array
• else search second half of array

Example: Search for key = 40 in array containing:
2, 5, 7, 10, 15, 31, 40, 55

Code for Binary Search:
public int binarySearch(int[] array, int key)
{
int low = 0;
int high = array.length - 1;

while(low <= high) // search elts in pos low to high
{
int mid = (low + high)/2; // middle pos in search range
if(array[mid] == key)
return mid;
else if(array[mid] < key) // search top half
low = mid+1;
else // search bottom half
high = mid-1;
}
return -1;
}

Algorithm Analysis for Binary Search

Example:
In an array of 64 elements, binary search eliminates half the array from consideration after each comparison. Repeatedly dividing by 2, we get:
32 elements after 1 comparison
16 elements after 2 comparisons
8 elements after 3 comparisons
4 elements after 4 comparisons
2 elements after 5 comparisons
1 element after 6 comparisons (note that 2^6 = 64)

So 6 comparisons are needed to search an array of 64 elts.

Note: Linear Search on average would do 64/2 = 32 comparisons.

Binary Search: n comparisons to search array of size 2^n.

Java's Arrays Class

• class in java.util package
• static methods that perform operations on arrays

 Method Name How it Works binarySearch(array, key) returns index of key in array, or -1 if array does not contain key fill(array, value) fills the entries in the array with value sort(array) rearranges the array entries into increasing order equals(array1, array2) returns true if the arrays contain the same entries in the same order toString(array) returns a String representation of the array

Using the Arrays class Methods

Example:

int[] nums = {-45, 3, 21, 84, 101, 147};
int pos = Arrays.binarySearch(nums, 84);
System.out.println("Position of 84: " + pos);

Output: Position of 84: 3

Example:
int[] nums = {2, 16, -4, 12, 101, 25};
Arrays.sort(nums);
int pos = Arrays.binarySearch(nums, -4);
System.out.println("Pos of -4: " + pos);
System.out.println(Arrays.toString(nums));

Output:
Pos of -4: 0
[-4, 2, 12, 16, 25, 101]

Example: Write a method that takes a sorted array of ints, and an int, and inserts the int into the array in the correct position. The last array entry is lost.

That is, if the array is {-1, 4, 17, 85, 100} and the value is 2,
then the array becomes {-1, 2, 4, 17, 85} after the method is called.

Exercise: Write a method called equal that takes two arrays of ints as arguments, and returns true if the arrays contain the same elements in the same order, and false otherwise.

Two-Dimensional Arrays

• used to represent tables with rows and columns
• 2 index values - first is row number, second is column number
• Indexing still starts at 0
• arrayName[i][j] is the entry at row i, col j
• If the array is a number type, the entries are set to 0 when the array is created. If the array is a reference type, the entries are are set to null when the array is created.
• An array of arrays - so the length of the array is the number of rows.

Declaring a 2-dimensional array:
int[][] myArr = new int[3][4]; // array of 3 rows, 4 cols

Initializing an Entry:
a[0][0] = 5;
a[0][1] = 17;

Example: Initializing all array entries to 1
int[][] myArr = new int[10][10]; //all entries are 0
for(int i = 0; i < myArr.length; i++)
{
// the number of elements in row i is   myArr[i].length
for(int j = 0; j < myArr[i].length; j++)
{
a[i][j] = 1;
}
}

Using an Initialization List

We can specify the elements in each row with an initialization list:
int[][] myArr = {{1, 2}, {3, 4}};

• the first row contains 1 and 2, the second row contains 3 and 4
• the compiler determines the number of rows by counting the number of sub-initializer lists in the main initializer list.
• the number of columns in a row is the number of values in the corresponding sub-initializer list.
• Different rows may have a different numbers of entries ("ragged array")
• double[][] fpArray = {{1, 2, 3}, {4, 5}, {6}};
• 1st row - 3 entries
• 2nd row - 2 entries
• 3rd row - 1 entry

Multi-Dimensional Array Examples

Example: Write a method that takes a 2-dim array of floating-point numbers, and returns the sum of all the entries in the array.

Example: Write a method that takes a 2-dim array of floating-point numbers and an int index, and returns the sum of the row with the specified index. If the index is not valid, return 0.

Example: Write a method that takes a square matrix (ie, an array with the same number of rows and cols) of ints, and returns the sum of the diagonal entries.

Example: Write a method that takes two arrays with the same dimensions, and adds them - it returns an array that contains the sum. In position i, j, the new array contains the sum of the entries in position i, j in the two arguments.

Sorting

Problem:
Given an array A[N] (ie, a one-dim array of N entries), arrange A's elements in ascending order.

2 basic operations in sorting algorithms:
• swap - exchange the position of 2 entries in the array
• pairwise comparison - determine which of 2 entries is largest

Note: What we mean by "largest" depends on the application-
• If the array contains Strings, "largest" could refer to dictionary order.
• If the array contains student records - e.g., objects of type Student - "largest" could mean the record containing the highest GPA, or student whose name comes last in alphabetical order.

Choosing a Sorting Algorithm

There are a number of different sorting algorithms - how do you choose the right one for your application?

Answer: To make a good choice, you must consider the number of swaps and the number of comparisons (to an array entry) each algorithm does.
• Sometimes comparisons are costly, e.g., it takes longer to compare 2 Strings than 2 ints
• Sometimes you may be willing to do more swaps to minimize the number of comparisons, but think about the time required for each operation.

Selection Sort

To sort A's entries into increasing order:

Step 0: Find smallest entry in A[0..N-1] and swap it with A[0].
Step 1: Find smallest entry in A[1..N-1] and swap it with A[1].
...
Step i: Find smallest entry in A[i..N-1] and swap it with A[i].

Solution grows from low end of the array. After step i, A[0], A[1], ..., A[i] contain the
correct values.

Example: Use selection sort to sort an array containing the values 3  1  10  7  2

Selection Sort Algorithm and Code

for i = 0 to N-2
find min of A[i], A[i+1], ..., A[N-1]. Call min A[minIndex].
Swap A[i] and A[minIndex].

public void selectionSort(double[] A)
{
for(int i = 0; i < A.length-1; i++)
{
// find the value that belongs in position i
minIndex = i;

for(int j = i+1; j < A.length; j++)
{
if(A[j] < A[minIndex]) minIndex = j;
}

// swap A[i] and A[minIndex]
double temp = A[i];
A[i] = A[minIndex];
A[minIndex] = temp;
}
}

Analysis of Selection Sort

Note:
Order of data does not affect number of swaps or comparisons done.

# of swaps: (in class)

# of comparisons: (in class)

There are faster sorting algorithms, but selection sort doesn't do a lot of swaps.

Insertion Sort

• Works the way many people sort a hand of playing cards
• Pick up 1 item at a time and put it in place among already sorted items

Step 1: The subarray A[0..0] is already sorted.
If A[1] is not in place in A[0..1], swap A[1] with A[0].
Now A[0..1] is sorted.

Step 2: The subarray A[0..1] is already sorted.
If current = A[2] is not in place in A[0..2], swap it with A[1].
If current is not in place in A[0..2], swap it with A[0].
Now A[0..2] is sorted.

...

Step i: Subarray A[0..i-1] is sorted.
If current = A[i] is not in place in A[0..i], swap current successively
with A[i-1], A[i-2], ... until current is in its correct place in A[0..i].
Now A[0..i] is sorted.

Example: 3  J  10  7  2

Psuedo-code:
For i = 0 to N-1
For(j = i; j > 0 && A[j] < A[j-1]; j--)
swap A[j] and A[j-1]

Example: Array containing 10  9  5  6