Unit 4 · 25 min

4.5 Implementing Array Algorithms

Every standard array algorithm is one traversal with a running result: pick the right start value and the right bounds.

Summary, objectives and course and exam description (CED) codes

The standard array algorithms are traversals that keep a running result: minimum or maximum, sum or average, whether at least one or all elements have a property, how many do, consecutive pairs, duplicates, shifting or rotating, and reversing. Each one is a loop plus the right starting value and the right loop bounds, and most exam errors come from those two choices.

By the end of this session you can

  • 4.5.A Develop code for standard and original algorithms for a particular context or specification that involves arrays, and determine the result of these algorithms.

4.5.A4.5.A.1

Reviewed against the CED on

Know this already? Jump to the checkpoint.

1LearnThe notes, the traps and how to remember them

1. Minimum and maximum

There are standard algorithms that use array traversals, and the first ones find a minimum or maximum value 4.5.A.1. The plan: start with the first element as the “best so far”, then compare every other element and replace the best when a new one beats it.

public static int findMax(int[] arr)
{
    int max = arr[0];
    for (int i = 1; i < arr.length; i++)
    {
        if (arr[i] > max)
        {
            max = arr[i];
        }
    }
    return max;
}
int[] depths = {-12, -4, -30, -7};
System.out.println(findMax(depths));

Output:

-4

Watch out: if max started at 0, this call would return 0, a value that is not even in the array. For a minimum, flip the comparison to <. To find the index of the max instead of the value, store maxIndex = 0 and compare arr[i] > arr[maxIndex].

2. Sum, average and count

To compute a sum, start at 0 and add every element. The average is the sum divided by the number of elements 4.5.A.1. To determine the number of elements having a particular property, start a counter at 0 and add 1 each time an element passes the test 4.5.A.1.

int[] goals = {2, 0, 3, 1, 4, 0, 1};

int sum = 0;
int count = 0;
for (int g : goals)
{
    sum += g;
    if (g >= 2)          // the property: 2 or more goals
    {
        count++;
    }
}
double average = (double) sum / goals.length;

System.out.println("Sum: " + sum);
System.out.println("Average: " + average);
System.out.println("Games with 2+ goals: " + count);
System.out.println("Integer division: " + sum / goals.length);

Output:

Sum: 11
Average: 1.5714285714285714
Games with 2+ goals: 3
Integer division: 1

Watch out: sum / goals.length with two int values is integer division. Cast one side to double first.

3. At least one, and all

To determine if at least one element has a property, return true as soon as you find one; only after checking every element can you return false 4.5.A.1. To determine if all elements have a property, return false as soon as one fails; only after the loop can you return true 4.5.A.1.

public static boolean anyFreezing(double[] temps)
{
    for (double t : temps)
    {
        if (t < 0)
        {
            return true;        // one is enough
        }
    }
    return false;               // checked them all, none found
}

public static boolean allPassing(int[] scores)
{
    for (int s : scores)
    {
        if (s < 60)
        {
            return false;       // one failure is enough
        }
    }
    return true;                // checked them all, none failed
}
double[] week = {3.5, 1.0, -2.0, 4.5};
int[] quiz = {75, 88, 59, 91};
System.out.println(anyFreezing(week));
System.out.println(allPassing(quiz));

Output:

true
false

Watch out: this version of allPassing is wrong, because it returns on the very first element:

public static boolean allPassingBroken(int[] scores)
{
    for (int s : scores)
    {
        if (s >= 60)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    return true;
}
int[] quiz = {75, 88, 59, 91};
System.out.println(allPassingBroken(quiz));

Output:

true

It looked only at 75 and stopped. The correct answer is false, because 59 fails.

4. Consecutive pairs and duplicates

To access all consecutive pairs of elements, look at arr[i] and arr[i + 1] 4.5.A.1. Because arr[i + 1] must be a valid index, the loop stops one early: i < arr.length - 1.

int[] steps = {4000, 6500, 6200, 9000, 12000};

for (int i = 0; i < steps.length - 1; i++)
{
    int change = steps[i + 1] - steps[i];
    System.out.println("Day " + i + " to day " + (i + 1) + ": " + change);
}

Output:

Day 0 to day 1: 2500
Day 1 to day 2: -300
Day 2 to day 3: 2800
Day 3 to day 4: 3000

With i < steps.length, the last pass would read steps[5] and throw an ArrayIndexOutOfBoundsException.

To determine the presence or absence of duplicate elements, compare each element with every element after it 4.5.A.1. The inner loop starts at i + 1, so no element is compared with itself and no pair is checked twice.

public static boolean hasDuplicate(String[] names)
{
    for (int i = 0; i < names.length; i++)
    {
        for (int j = i + 1; j < names.length; j++)
        {
            if (names[i].equals(names[j]))
            {
                return true;
            }
        }
    }
    return false;
}
String[] signUps = {"Ada", "Ben", "Cleo", "Ben"};
String[] team = {"Ada", "Ben", "Cleo"};
System.out.println(hasDuplicate(signUps));
System.out.println(hasDuplicate(team));

Output:

true
false

Watch out: if the inner loop started at j = 0, every name would be compared with itself and the method would always return true. Use equals, not ==, to compare String objects.

5. Shift and rotate

To shift elements left, every element moves to the index one lower and the first value is lost. To rotate left, you save that first value and put it in the empty last spot 4.5.A.1.

int[] queue = {10, 20, 30, 40, 50};

int first = queue[0];                       // save the value that falls off
for (int i = 0; i < queue.length - 1; i++)
{
    queue[i] = queue[i + 1];                // move each element one place left
}
queue[queue.length - 1] = first;            // rotate: wrap it around

for (int q : queue)
{
    System.out.print(q + " ");
}
System.out.println();

Output:

20 30 40 50 10 
index 0 1 2 3 4
before 10 20 30 40 50
after shift left (last spot not set yet) 20 30 40 50 50
after rotate left 20 30 40 50 10

A plain shift left stops after the loop; the last spot usually gets a filler value such as 0.

To shift or rotate right, the loop must run backward, from the end toward index 1. Otherwise each value overwrites the next one before it is moved.

int[] queue = {10, 20, 30, 40, 50};

int last = queue[queue.length - 1];
for (int i = queue.length - 1; i > 0; i--)
{
    queue[i] = queue[i - 1];
}
queue[0] = last;

for (int q : queue)
{
    System.out.print(q + " ");
}
System.out.println();

Output:

50 10 20 30 40 

Watch out: a forward loop for a right shift copies the first value everywhere:

int[] queue = {10, 20, 30, 40, 50};
for (int i = 1; i < queue.length; i++)
{
    queue[i] = queue[i - 1];
}
for (int q : queue)
{
    System.out.print(q + " ");
}
System.out.println();

Output:

10 10 10 10 10 

6. Reverse

To reverse the order of the elements in place, swap the first and last, then the second and second-to-last, and so on until the middle 4.5.A.1. The mirror of index i is arr.length - 1 - i. A swap needs a temporary variable.

String[] podium = {"gold", "silver", "bronze", "fourth", "fifth"};

for (int i = 0; i < podium.length / 2; i++)
{
    String temp = podium[i];
    podium[i] = podium[podium.length - 1 - i];
    podium[podium.length - 1 - i] = temp;
}
for (String p : podium)
{
    System.out.print(p + " ");
}
System.out.println();

Output:

fifth fourth bronze silver gold 
index 0 1 2 3 4
before “gold” “silver” “bronze” “fourth” “fifth”
after i = 0 (swap 0 and 4) “fifth” “silver” “bronze” “fourth” “gold”
after i = 1 (swap 1 and 3) “fifth” “fourth” “bronze” “silver” “gold”

The loop stops when i reaches 5 / 2, which is 2; the middle element stays put. If the loop ran to podium.length, it would swap every pair a second time and put the array back in its original order.

A second way is to build a new array, filling it from the back of the original:

int[] laps = {61, 59, 64, 58};
int[] reversed = new int[laps.length];
for (int i = 0; i < laps.length; i++)
{
    reversed[laps.length - 1 - i] = laps[i];
}
for (int lap : reversed)
{
    System.out.print(lap + " ");
}
System.out.println();

Output:

58 64 59 61 

Lock it in: memory hooks

  • Min and maxCrown the first, then challenge: start with arr[0] and replace it only when someone beats it.
  • Any versus allAny: one yes is enough, return true early. All: one no is enough, return false early.
  • PairsPairs stop one early: i < length - 1, because arr[i + 1] must exist.
  • RotateRotate is shift plus a saved passenger: save the end that falls off, then put it back at the other end.

Common misconceptions

  • "Start a maximum at 0."

    Not quite. If every value is negative, 0 is returned even though it is not in the array. Start with the first element, arr[0].

  • "sum / arr.length gives the exact average."

    Not quite. If sum is an int, that is integer division and the decimal part is lost. Cast first: (double) sum / arr.length.

  • "To check if all elements pass, return true as soon as one passes."

    Not quite. One passing element proves nothing about the rest. Return false as soon as one fails, and return true only after the loop ends.

  • "To reverse an array, swap every index with its mirror from 0 to length - 1."

    Not quite. Swapping all the way through undoes the work, so the array ends up unchanged. Stop at the middle: i < arr.length / 2.

Exam traps

  • A max that starts at 0 fails when all values are negative; a min that starts at 0 fails when all values are positive.
  • Integer division in an average: 7 / 2 is 3, not 3.5.
  • An if with return true and an else with return false inside the loop only checks the first element.
  • Shifting right must go from the end backward, or one value gets copied into every element.
  • Reverse with a loop to arr.length (not arr.length / 2) puts every element back where it started.

2PracticeRecall it, then check yourself

In 30 seconds

  1. Min or max: start with arr[0], compare every element, update when a new best appears.
  2. Sum: start at 0 and add each element. Average: cast to double before dividing.
  3. At least one: return true when found, false after the loop. All: return false when one fails, true after the loop.
  4. Count: start at 0, add 1 for each element with the property.
  5. Consecutive pairs use arr[i] and arr[i + 1] with i < arr.length - 1. Duplicates compare each element with every later one.
  6. Shift moves every element one place and loses an end value; rotate saves that value and wraps it around; reverse swaps mirror pairs up to the middle.

Cover this list, say the points out loud, then take the checkpoint without scrolling back up.

Checkpoint · 6 questions

Checkpoint: Implementing Array Algorithms

Pick an answer to mark it. Every answer is explained, and you can try any question again. Your saved score counts first tries only, and stays in this browser.

  1. 1 The following method is intended to return the largest value in nums. For which of the following arrays does the method NOT return the largest value? 4.5.A.1
    public static int largest(int[] nums)
    {
        int max = 0;
        for (int n : nums)
        {
            if (n > max)
            {
                max = n;
            }
        }
        return max;
    }
    Show answer

    Answer: C. max starts at 0, so when every element is negative no element is greater than 0 and the method returns 0, which is not in the array (the answer should be -2). In the other arrays the largest value is at least 0, so it replaces the starting value. Starting with max = nums[0] fixes the bug.

  2. 2 Consider the following code segment. What is printed as a result of executing the code segment? 4.5.A.1
    int[] t = {3, 4, 4};
    int sum = 0;
    for (int x : t)
    {
        sum += x;
    }
    double avg = sum / t.length;
    System.out.println(avg);
    Show answer

    Answer: A. sum is 11 and t.length is 3, both int, so sum / t.length is integer division and gives 3, which is then stored in a double as 3.0. "3" would need an int variable, 3.6666666666666665 needs a cast before dividing, and 4.0 assumes rounding, which integer division never does.

  3. 3 The following method is intended to return true if all elements of arr are positive and false otherwise. For which of the following arrays does the method return an incorrect result? 4.5.A.1
    public static boolean allPositive(int[] arr)
    {
        for (int i = 0; i < arr.length; i++)
        {
            if (arr[i] > 0)
            {
                return true;
            }
        }
        return false;
    }
    Show answer

    Answer: D. The method returns true as soon as one element is positive, so it checks "at least one" instead of "all". For {4, -1, 2} it returns true after looking at 4, but the correct answer is false. For {-3, -5} and {0, 0} it correctly returns false, and for {1, 2, 3} it correctly returns true.

  4. 4 Consider the following code segment. What is printed as a result of executing the code segment? 4.5.A.1
    int[] h = {3, 6, 5, 8, 8, 9};
    int c = 0;
    for (int i = 0; i < h.length - 1; i++)
    {
        if (h[i + 1] > h[i])
        {
            c++;
        }
    }
    System.out.println(c);
    Show answer

    Answer: B. The loop compares consecutive pairs: 3 to 6 (increase), 6 to 5, 5 to 8 (increase), 8 to 8 and 8 to 9 (increase), so c is 3. "4" counts 8 to 8 as an increase (>=), "2" stops one pair early and misses 8 to 9, and "5" counts every pair.

  5. 5 Consider the following code segment. What is printed as a result of executing the code segment? 4.5.A.1
    int[] q = {1, 2, 3, 4, 5};
    int temp = q[q.length - 1];
    for (int i = q.length - 1; i > 0; i--)
    {
        q[i] = q[i - 1];
    }
    q[0] = temp;
    for (int x : q)
    {
        System.out.print(x + " ");
    }
    Show answer

    Answer: C. The code rotates right: it saves the last value (5), moves every element one place right going backward, then puts 5 at index 0. "2 3 4 5 1" is a rotate left, "1 1 2 3 4" is a shift right without putting the saved value back, and "5 4 3 2 1" is a reverse.

  6. 6 Consider the following method. Which of the following best describes what check returns? 4.5.A.1
    public static boolean check(String[] w)
    {
        for (int i = 0; i < w.length; i++)
        {
            for (int j = 0; j < w.length; j++)
            {
                if (i != j && w[i].equals(w[j]))
                {
                    return true;
                }
            }
        }
        return false;
    }
    Show answer

    Answer: B. The nested loops compare every pair of different positions (i != j) and return true as soon as two of them hold equal strings, so the method detects duplicates. Without i != j it would return true for any non-empty array; it does not need all elements equal, and it checks every pair, not only the first and last.

3PrevailLock it in for exam day

By the numbers

Name each list from memory, then reveal it to check. Each list shows how many items to recall.

  • Standard algorithms that use array traversals nine algorithms CED 4.5.A.1
    1. determine a minimum or maximum value
    2. compute a sum or average
    3. determine if at least one element has a particular property
    4. determine if all elements have a particular property
    5. determine the number of elements having a particular property
    6. access all consecutive pairs of elements
    7. determine the presence or absence of duplicate elements
    8. shift or rotate elements left or right
    9. reverse the order of the elements

Key terms: flip the cards

Read the term, say the definition out loud, then flip to check. Struggling a little to remember is what makes it stick.

  • Traversaltap to flip

    Using repetition (or recursion) to access all elements of an array or ArrayList, or an ordered sequence of them.

    Example and CED codes
  • Arraytap to flip

    An object that stores a fixed number of values of the same type, either primitive values or object references, reached by an index.

    Example and CED codes
  • Elementtap to flip

    One value stored in an array or an ArrayList, at a position given by its index.

    Example and CED codes
  • Indextap to flip

    The position of a character in a String, counted from 0. Valid indices run from 0 to length() - 1.

    Example and CED codes
  • Enhanced for looptap to flip

    A loop that assigns a copy of each element of an array or ArrayList, in order, to its loop variable, without using an index.

    Example and CED codes
  • Algorithmtap to flip

    A step-by-step process for completing a task or solving a problem, written in words or drawn as a diagram such as a flowchart.

    Example and CED codes

Questions students ask

How do you find the largest value in an array in Java?

Store arr[0] in a variable, traverse the rest of the array and replace the stored value whenever an element is greater. After the loop, the variable holds the maximum.

What is the difference between shifting and rotating an array?

Both move every element one place. A shift loses the value that falls off one end; a rotate saves that value and puts it in the empty spot at the other end.

How do you check an array for duplicates?

Use nested loops: for each index i, compare arr[i] with every arr[j] where j starts at i + 1. If any pair is equal, there is a duplicate.

Why does my reverse method leave the array unchanged?

The loop probably runs over the whole array, so each pair is swapped twice. Run it only while i < arr.length / 2.

Was this page helpful?

No names are ever shown, and every public comment is checked by us first. Please do not include personal details. To get a reply, email [email protected].

↑ Top

Enlarged view of the selected figure