CISC 1115
Introduction to Programming Using Java
Lecture #12
Techniques III — Arrays
Common Operations/Techniques on Arrays
First element
arr[0]
Last element
arr[arr.length-1]
Middle element
- The following index formula returns the 'left' middle element for an array with an even number of elements
arr[(arr.length-1)/2]
'Mirror' element
- The first element is mirrored by the last, the second with the next to the last, etc.
- If the array has an odd number of elements, the middle is mirrored with itself.
- The mirror of the i'th element is:
arr[arr.length-1-i]
Traversing an array
Traversing an array backwards
- Explicit index only — the enhanced for loop only iterates forward
for (int i = arr.length-1; i >= 0; i--) {
// use arr[i]
…
}
Traversing an array until some condition
- Using a boolean flag
boolean done = false;
for (int i = 0; i < arr.length && !done; i++) {
// use arr[i]
…
if (some condition)
done = true;
…
}
- Using a
break statement
for (int i = 0; i < arr.length; i++) {
// use arr[i]
…
if (some condition)
break;
…
}
- Enhanced for loop has no facility for extra conditionals — must use break
for (double e : arr)
// use arr[i]
…
if (some condition)
break;
…
}
Traversing an array backwards until some condition
- Same basic idea — backwards iteration + condition — can use boolean flag:
boolean done = false;
for (int i = arr.length-1; i >= 0 && !done; i--) {
// use arr[i]
…
if (some condition)
done = true;
…
}
- or
break
for (int i = arr.length-1; i >= 0; i--) {
// use arr[i]
…
if (some condition)
break;
…
}
Traversing using a while loop
Printing an array
void print(double [] arr) {
System.out.print("{");
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i]+ " ");
System.out.print("}");
}
Printing an array (with comma logic)
void print(double [] arr) {
System.out.print("{");
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i]);
if (i < arr.length-1) System.out.print(", ");
}
System.out.print("}");
}
Comma logic using the conditional operator
void print(double [] arr) {
System.out.print("{");
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + (i < arr.length-1 ? ", " : "");
}
System.out.print("}");
}
Reading in an array using a header value
double [] read(Scanner scanner) {
int numVals = scanner.nextInt();
double [] arr = new double[numVals];
for (int i = 0; i < numVals; i++)
arr[i] = scanner.nextDouble();
return arr;
}
- Note how we can allocate the exact size of the array here
- probably not a good idea anyway, though
- Can't use enhanced for-loop, we're assigning to the array elements (the enhanced for would only assign to the 'dummy'
local variable introduced in the 'for' header).
Finding the maximum/minimum of an array
- Assumes array is not empty
- Also note don't use enhanced for (loop starts at 1)
- Actually could, but would have an extra unnecessary comparison of arr[0]
double max(double [] arr) {
double result = arr[0];
for (int i = 1; i < arr.length; i++)
if (arr[i] > result) result = arr[i];
return result;
}
Finding the sum of an array
double sum(double [] arr) {
double result = 0;
for (double e: arr)
result += e;
return result;
}
Finding the average of an array
- Empty arrays don't work here either (division by 0)
- Note the use of composition; using pre-existing (and presumably working) methods
to create new methods/functionality is a technique known as delegation or leveraging
double average(double [] arr) {return sum(arr) / arr.length;}
(Linear) Searching an array: find and contains
- find is often used for the name of the method that searches for the value and returns its position (index)
- contains is often used for the name of the method that simply returns if the value is present in the array
int find(double [] arr, double val) {
for (int i = 0; i < arr.length; i++)
if (val == arr[i]) return i;
return -1; // -1 is never a valid index, so it's a good indicator that 'val' wasn't found
}
- The
return -1 is after the loop; you can't state the value is not there until you've traversed the entire array.
- We can now leverage
find for our definition of a contains method
boolean contains(double [] arr, double val) {return find(arr, val) != -1;}
Copying (cloning) an array
double [] copy(double [] arr) {
double [] newArr = new double[arr.length];
for (int i = 0; i < arr.length; i++)
newArr[i] = arr[i];
return newArr;
}
- Can't use enhanced for loop — need subscript to assign from one array to the other
Swapping two elements of an array
void swap(double [] arr, int i, int j) {
double t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
A surprising result: the impossibility of direct swapping
void swap(int x, int y) {
int t = x;
x = y;
y = t;
}
void swap(String s1, String s2) {
String t = s1;
s1 = s2;
s2 = t;
}
Reversing an array
- In-place:
void reverse(double [] arr) {
for (int i = 0; i < mid(arr); i++)
swap(arr, i; mirror(i));
}
- Main 'gotcha!': should not go through entire array … only go halfway through the array
- Return new array (no halfway):
double [] reverse(double [] arr) {
double [] newArr = new double[arr.length];
for (int i = 0; i < arr.length; i++)
newArr[i] = mirror(arr, i));
}
Determine if the are any duplicates in an array
The technique used for finding duplicates in a file is similar to that used for various array sorting techniques:
- Loop through the array — it can be forward or backward depending on the algorithm
- In our case we'll begin with the first element, and proceed forward from there
- We'll speak of the element we're working with as the current element.
- Move forward in the array from the element after (to the right of) the current element, and test each
for equality with the current element.
- This involves a second inner loop
boolean hasDups(double [] arr) {
for (int i = 0; i < arr.length; i++)
for (int j = i+1; j < arr.length; j++)
if (arr[i] == arr[j]) return true;
return false;
}
- Checking for the existence of duplicates can stop as soon as one is found
- Counting duplicates requires continuing to the end of the array for both loops, and involves a bit more logic
(to prevent duplicate values from being counted again later on).
The inner loop begins its processing at increasing indexs — the first time at index 1, the second at index 2, etc
- We can think of the inner loop as working on a subarray i.e., a portion of the array
- In this case the subarrays began at increasing indexes, but always terminated at arr.length-1
- We will see more about subarrays in a succeeding 'Techniques' lecture.
Another Approach Using a 'Helper' Method
boolean hasDups(double [] arr) {
for (int i = 0; i < arr.length; i++)
if (contains(arr, i+1, arr.length-1, arr[i]) return true;
return false;
}
boolean contains(double [] arr, int start, int end, double val) {
for (int i = start; i <= end; i++)
if (arr[i] == val) return true;
return false;
}
- The
contains method is somewhat 'customized' to our situation, it searches a subsequence of the array (a subarray)
- As it turns out, this is not such a 'unique' situation that such a method would be useless elsewhere
- We sometimes call a method such as
contains a because it is introduced to 'help' the calling hasDups method
Merging two sorted arrays to a third
Sorting an array
Sorting has its own lecture.
Determine if the are any duplicates in a sorted array
How is this different than the determining duplicates above? Is it harder? Easier?
Rotating an array
Rotating an array is similar in concept to rotating three elements but it's done in a loop from beginning to end
or end to beginning depending on a left or right shift.
Shifting an array
Shifting an array is similar in concept to shifting three elements but it's done in a loop from beginning to end
or end to beginning depending on a left or right shift.
Reading in an array (from a file) using a trailer value or eof by doing a pre-scan of the file
Scanner = new Scanner(new File(…));
// Open the file, read the file completely and count the number of values
int count = 0;
while (scanner.hasNextInt()) {
scanner.nextInt();
count++;
}
scanner.close();
// We now know how many values are in the file; create the proper size array and read them in
double [] arr = new double[count];
// Open the file again, this time for reading
scanner = new Scanner(new File(…));
for (int i = 0; i < count; i++)
arr[i] = scanner.nextInt();
What we usually do instead — in such a situation — is cdeclare an array bigger then we could possibly need, and keep track of
the number of elements we read into it.
- This approach will be covered a bit later