SEN1001 · Week 7 · Arrays II

Array algorithms and ArrayList

Linear search, counting, reversing in place, the difference between a real copy and an alias, shifting and checking whether sorted; then ArrayList, the list whose size can change, and its methods. On the exam it comes both as tracing and as writing short methods.

linear searchsentinel value -1reverse in placearray copyaliasArrays.copyOfArrays.equalsArrays.sortArrayListgeneric typewrapper classIntegerautoboxingaddgetsetremovesizecontainsindexOf

You know how to create and traverse an array. This week covers the standard jobs done with it: searching, counting, reversing, copying, shifting. They are all patterns of a few lines, and they come up again and again as “write a method” questions on the exam. In the second half you will learn ArrayList, which solves the size problem of arrays.

Golden rules:

  1. A search returns as soon as it finds the key; if it does not, -1 after the loop.
  2. In an in-place reversal the loop goes only halfway: i < length / 2.
  3. b = a is not a copy. For a copy, create a new array.
  4. In ArrayList the size is size(), the element is get(i). No square brackets.
  5. If you delete elements in a loop, go from the end to the start.

Linear search and counting

public static int linearSearch(int[] arr, int key) {
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == key) return i;     // found it, leave immediately
    }
    return -1;                           // never found
}
public static int count(int[] arr, int key) {
    int c = 0;
    for (int x : arr) if (x == key) c++;
    return c;
}
// in main:
int[] a = {8, 3, 5, 3, 1};
System.out.println(linearSearch(a, 3) + " " + linearSearch(a, 1) + " " + linearSearch(a, 7));
System.out.println(count(a, 3));
1 4 -1
2

-1 is not a valid index, so it is used to mean “not found”. The return -1 line must be outside the loop. If you put it in an else inside, you only check the first element.

Reversing in place

Swap the first with the last, then the second with the second from the end, up to the middle.

public static void reverse(int[] arr) {
    for (int i = 0; i < arr.length / 2; i++) {
        int temp = arr[i];
        arr[i] = arr[arr.length - 1 - i];
        arr[arr.length - 1 - i] = temp;
    }
}

For {1, 2, 3, 4, 5} and {1, 2, 3, 4}:

[5, 4, 3, 2, 1]
[4, 3, 2, 1]
i   indexes swapped          array (5 elements)
0   0 ↔ 4                    [5, 2, 3, 4, 1]
1   1 ↔ 3                    [5, 4, 3, 2, 1]
2   loop ends (2 < 5/2 = 2 is false), the middle 3 stays in place

PITFALL · going all the way to the end. If you make the loop i < arr.length, it reverses in the first half and reverses back in the second half. In verification this version left the array as [1, 2, 3, 4, 5], that is, unchanged.

Copy and alias

int[] orig = {1, 2, 3};
int[] alias = orig;                              // the same array
int[] real = copy(orig);                         // a copy made with a loop
int[] c2 = Arrays.copyOf(orig, orig.length);     // a ready-made copy
orig[0] = 99;
System.out.println(alias[0] + " " + real[0] + " " + c2[0]);
System.out.println((orig == alias) + " " + (orig == real));
int[] x1 = {1, 2}, x2 = {1, 2};
System.out.println((x1 == x2) + " " + Arrays.equals(x1, x2));
99 1 1
true false
false true

A copy with a loop is written like this:

public static int[] copy(int[] arr) {
    int[] result = new int[arr.length];
    for (int i = 0; i < arr.length; i++) result[i] = arr[i];
    return result;
}

With arrays, == does not look at the contents; it looks at whether two variables point to the same array. For content comparison use Arrays.equals (or your own loop).

Sorted? Shifting. Sorting.

public static boolean isSorted(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {     // length-1 because we use i+1
        if (arr[i] > arr[i + 1]) return false;
    }
    return true;
}
public static void shiftLeft(int[] arr) {          // rotate left
    int first = arr[0];
    for (int i = 0; i < arr.length - 1; i++) arr[i] = arr[i + 1];
    arr[arr.length - 1] = first;
}

isSorted({1, 3, 3, 7}), isSorted({1, 5, 2}), shiftLeft({10, 20, 30, 40}) and Arrays.sort({5, 2, 9, 1}):

true false
[20, 30, 40, 10]
[1, 2, 5, 9]

TIP · if you see i + 1, lower the bound. If you use arr[i + 1] in the loop, the last iteration must be i = length - 2, otherwise you go outside the array in the last iteration. The condition is i < arr.length - 1.

ArrayList: an array whose size can change

The size of an array is fixed from the start. If you do not know how many elements will come (read numbers until the user enters -1, delete elements from a list), you use ArrayList. It grows and shrinks by itself.

import java.util.ArrayList;

ArrayList<String> names = new ArrayList<>();
names.add("Ali");
names.add("Can");
names.add("Ece");
System.out.println(names + " " + names.size());
names.add(1, "Bora");          // insert at index 1, the rest shifts
System.out.println(names);
System.out.println(names.get(2));
names.set(0, "Arda");          // replace
System.out.println(names);
names.remove(3);               // delete by index
System.out.println(names);
names.remove("Bora");          // delete by value
System.out.println(names);
System.out.println(names.contains("Can") + " " + names.indexOf("Can") + " " + names.indexOf("Zeynep"));
System.out.println(names.isEmpty());
[Ali, Can, Ece] 3
[Ali, Bora, Can, Ece]
Can
[Arda, Bora, Can, Ece]
[Arda, Bora, Can]
[Arda, Can]
true 1 -1
false
ArrayArrayListWhat it does
new int[5]new ArrayList<Integer>()create
a.lengthlist.size()number of elements
a[i]list.get(i)read
a[i] = xlist.set(i, x)replace
(none)list.add(x), list.add(i, x)add
(none)list.remove(i), list.remove(x)delete
search with a looplist.contains(x), list.indexOf(x)search

If you call get with an invalid index it crashes: IndexOutOfBoundsException: Index 1 out of bounds for length 1.

Wrapper classes and autoboxing

ArrayList holds only objects, not primitives. ArrayList<int> does not compile (unexpected type). Every primitive has a wrapper class: int → Integer, double → Double, char → Character, boolean → Boolean. Java does the conversion between them by itself (autoboxing / unboxing):

ArrayList<Integer> nums = new ArrayList<>();
for (int i = 1; i <= 5; i++) nums.add(i * 10);     // int → Integer automatically
System.out.println(nums);
nums.remove(1);                                    // INDEX 1
System.out.println(nums);
nums.remove(Integer.valueOf(40));                  // VALUE 40
System.out.println(nums);
int first = nums.get(0);                           // Integer → int automatically
System.out.println(first + 1);
for (int i = 0; i < nums.size(); i++) System.out.print(nums.get(i) + " ");
[10, 20, 30, 40, 50]
[10, 30, 40, 50]
[10, 30, 50]
11
10 30 50 

PITFALL · remove(1) or remove(value)? In an Integer list, remove(1) takes an int argument, so it deletes index 1. If you want to delete the value 1, write remove(Integer.valueOf(1)). In a String list there is no confusion: remove("Bora") deletes the value.

Deleting in a loop

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(2, 4, 5, 6, 7));
for (int i = 0; i < list.size(); i++) {
    if (list.get(i) % 2 == 0) list.remove(i);      // from the start: WRONG
}
System.out.println(list);
ArrayList<Integer> list2 = new ArrayList<>(Arrays.asList(2, 4, 5, 6, 7));
for (int i = list2.size() - 1; i >= 0; i--) {
    if (list2.get(i) % 2 == 0) list2.remove(i);    // from the end: CORRECT
}
System.out.println(list2);
[4, 5, 7]
[5, 7]

When going from the start, after 2 is deleted, 4 shifted to index zero, but because i moved on to 1, 4 was never checked. If you go from the end, the elements to the right of a deleted element have already been checked.

Common mistakes

Wrong ideaThe truth
return -1 inside the loop in an elseAfter the loop
The reversal loop is i < lengthi < length / 2, otherwise it reverses back
int[] b = a; is a copyThe same array; Arrays.copyOf or a loop
a == b compares contentsReferences; use Arrays.equals
arr[i + 1] with i < lengthi < length - 1
ArrayList<int>ArrayList<Integer>
list.length, list[i]list.size(), list.get(i)
list.set(i, x) insertsIt replaces; the size does not change
In an Integer list remove(5) deletes 5It deletes index 5
Deleting while going from the start is safeElements are skipped; go from the end

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

Using linearSearch (returns the first index of key, or -1) and count (returns how many times key appears), what is printed?

int[] a = {4, 7, 4, 2, 4};
System.out.println(linearSearch(a, 4) + " " + count(a, 4) + " " + linearSearch(a, 9));
Show answer
0 3 -1

linearSearch returns at the first match: index 0. count walks the whole array: there are three 4s. There is no 9: -1.

Question 2medium

What is printed?

int[] a = {1, 2, 3, 4, 5, 6};
for (int i = 0; i < a.length / 2; i++) {
    int t = a[i];
    a[i] = a[a.length - 1 - i];
    a[a.length - 1 - i] = t;
}
System.out.println(a[0] + " " + a[2] + " " + a[5]);
Show answer
6 4 1

Reverse in place: for i = 0, 1, 2 the element at the front and its partner at the end are swapped. The array becomes {6, 5, 4, 3, 2, 1}. a[0] = 6, a[2] = 4, a[5] = 1.

Question 3medium

What is printed?

int[] a = {3, 6, 9};
int[] b = a;
int[] c = Arrays.copyOf(a, 3);
b[0] = 0;
c[1] = 0;
System.out.println(a[0] + " " + a[1]);
Show answer
0 6

b points to the same array as a (alias); b[0] = 0 changes a too. c is a real copy, a separate array; c[1] = 0 does not touch a.

Question 4medium

What is printed?

int[] a = {1, 2, 3, 4, 5};
for (int i = 0; i < a.length - 1; i++) a[i] = a[i + 1];
System.out.println(Arrays.toString(a));
Show answer
[2, 3, 4, 5, 5]

Each element takes the one to its right: a shift to the left. The last element stays in place (the loop stops at length - 1), so 5 appears twice. The first element (1) is gone; if you wanted a rotation, you would save it at the start and put it at the end.

Question 5medium

What is printed?

ArrayList<String> list = new ArrayList<>();
list.add("x");
list.add("y");
list.add(0, "z");
list.add("w");
list.set(2, "v");
System.out.println(list + " " + list.size());
Show answer
[z, x, v, w] 4

add appends to the end: [x, y]. add(0, "z") inserts at the front and shifts the others: [z, x, y]. w at the end: [z, x, y, w]. set(2, "v") puts v in place of the y at index 2 (the size does not change).

Question 6hard

What is printed?

ArrayList<Integer> list = new ArrayList<>();
list.add(5); list.add(10); list.add(15); list.add(20);
list.remove(1);
list.remove(Integer.valueOf(20));
System.out.println(list);
Show answer
[5, 15]

remove(1) with an int argument deletes index 1 (10). remove(Integer.valueOf(20)) with an object argument deletes the element whose value is 20. In Integer lists this difference is a classic trap.

Question 7hard

What is printed?

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 3, 3, 8));
for (int i = 0; i < list.size(); i++) {
    if (list.get(i) == 3) list.remove(i);
}
System.out.println(list);
Show answer
[3, 8]

i = 0: 3 is deleted, the list becomes [3, 3, 8] and the elements shift left. i = 1: get(1) = 3, deleted: [3, 8]. i = 2: 2 < 2 is false, the loop ends. The first 3 was skipped, because the element that shifted after the deletion was not checked. The fix: traverse from the end to the start.

Question 8medium

What is printed?

ArrayList<String> list = new ArrayList<>(Arrays.asList("cat", "dog", "cow"));
int total = 0;
for (String s : list) if (s.startsWith("c")) total += s.length();
System.out.println(total + " " + list.indexOf("cow") + " " + list.contains("Dog"));
Show answer
6 2 false

Those starting with c are cat and cow: 3 + 3 = 6. cow is at index 2. contains searches with equals and is case-sensitive: there is no "Dog".

Question 9easy

Using isSorted (returns true if every element is <= the next one), what is printed?

int[] a = {2, 8, 5};
System.out.println(isSorted(a));
Arrays.sort(a);
System.out.println(isSorted(a) + " " + a[1]);
Show answer
false
true 5

Because 8 > 5, the first check is false. Arrays.sort sorts the array in place from smallest to largest: {2, 5, 8}. Now it is sorted, and the middle element is 5.

Question 10medium

What is printed?

int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println((a == b) + " " + Arrays.equals(a, b));
Show answer
false true

== checks whether two references point to the same array; a and b are two separate arrays. Arrays.equals compares element by element.

Question 11medium

Write a static method reversedCopy(int[] arr) that returns a NEW array with the elements in reverse order and leaves arr unchanged.

Show answer
result[i] = arr[arr.length - 1 - i];

The new array is created with the same size. Element i is the i-th element from the end of the original.public static int[] reversedCopy(int[] arr) { int[] result = new int[arr.length]; for (int i = 0; i < arr.length; i++) { result[i] = arr[arr.length - 1 - i]; } return result;}Test: {1, 2, 3, 4} → arr is still [1, 2, 3, 4], the result is [4, 3, 2, 1].

Question 12hard

Write a static method removeNegatives(ArrayList<Integer> list) that removes every negative number from the list.

Show answer
for (int i = list.size() - 1; i >= 0; i--) if (list.get(i) < 0) list.remove(i);

If you traverse from the end to the start, when an element is deleted the elements that shift have already been checked; nothing is skipped.public static void removeNegatives(ArrayList<Integer> list) { for (int i = list.size() - 1; i >= 0; i--) { if (list.get(i) < 0) list.remove(i); }}Test: [-1, -2, 5, -3, 4, -6] → [5, 4]. If you had traversed from the start and deleted, one of the consecutive negatives would have been skipped.

Verification: All outputs were run with JDK 26 (verify/SEN1001/W07.java and W07b.java). The ArrayList<int> compile error was obtained from verify/SEN1001/err/Prim.java, and the get out-of-bounds error from err/Get.java.

Review card

Linear search: for i... if (arr[i] == key) return i; after the loop return -1; Counting: c = 0; for (x : arr) if (x == key) c++; Reverse (in place): i < length/2, swap arr[i] ↔ arr[length-1-i] (if you go up to length you swap twice = no change) b = a → alias, same array real copy: a loop or Arrays.copyOf(a, a.length) a == b compares references Arrays.equals(a, b) the elements Arrays.sort(a) smallest to largest Sorted?: i < length - 1, if (arr[i] > arr[i+1]) return false; import java.util.ArrayList; ArrayList<String> list = new ArrayList<>(); ArrayList<int> does NOT exist → ArrayList<Integer> (wrapper: Integer Double Character Boolean) add(x) at the end add(i, x) insert get(i) set(i, x) remove(i) remove(object) size() contains(x) indexOf(x) (-1 if absent) isEmpty() clear() Array: a.length, a[i] List: list.size(), list.get(i) In an Integer list remove(1) deletes the index, remove(Integer.valueOf(1)) deletes the value Deleting in a loop → traverse from the end to the start println(list) → [a, b, c] (printed properly, unlike an array)