Project Based Learning in Java

Applied Array Algorithms

Linear search, conditional aggregation, matrix processing, and argument validation.

Applied Topic CO1 aligned Unit 1

Learning outcome: Apply array traversal to searching, conditional aggregation, command-line input, and two-dimensional data processing.

Knowing the syntax of an array is only the beginning. Most array programs follow a small number of reusable patterns: visit every element, stop when a target is found, maintain an accumulated result, or compare each value with the best value seen so far.

Linear search examines elements from the beginning until it finds the required value. If the value is absent, the method returns -1.

In simple terms: Linear search is looking for a name on an unsorted guest list: start at the top and read every line until it turns up. Returning -1 is the honest way of saying the walk finished and the name was never there.

public class LinearSearch {
    static int findIndex(int[] values, int target) {
        for (int index = 0; index < values.length; index++) {
            if (values[index] == target) {
                return index;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] numbers = {18, 7, 42, 11, 29};
        int position = findIndex(numbers, 42);
        System.out.println(position);
    }
}

The algorithm has a worst-case time complexity of O(n) because it may inspect every element.

Finding the Greatest Value

Initialise the greatest value from the first array element rather than using 0, because all supplied values may be negative.

In simple terms: Starting from 0 is like assuming the shortest person in the room is at least average height. If every value is negative, nothing ever beats 0 and the answer comes back wrong.

static int greatest(int[] values) {
    if (values.length == 0) {
        throw new IllegalArgumentException("Array must not be empty");
    }

    int greatest = values[0];
    for (int index = 1; index < values.length; index++) {
        if (values[index] > greatest) {
            greatest = values[index];
        }
    }
    return greatest;
}

The same pattern can find the smallest value by changing the comparison.

Conditional Sum with a State Flag

Some problems require the program to ignore a section of the array. In this example, values beginning with 6 and ending with the next 7, including both boundary values, are excluded from the sum.

In simple terms: The flag is a light switch. Seeing a 6 turns it off and the totalling pauses; the next 7 turns it back on. The loop still visits every element — the switch only decides which ones count.

public class ConditionalArraySum {
    static int sumOutsideSixToSeven(int[] values) {
        int sum = 0;
        boolean ignoring = false;

        for (int value : values) {
            if (!ignoring && value == 6) {
                ignoring = true;
            } else if (ignoring && value == 7) {
                ignoring = false;
            } else if (!ignoring) {
                sum += value;
            }
        }

        if (ignoring) {
            throw new IllegalArgumentException("A 6 has no closing 7");
        }
        return sum;
    }

    public static void main(String[] args) {
        int[] values = {1, 2, 6, 99, 7, 3};
        System.out.println(sumOutsideSixToSeven(values)); // 6
    }
}

The Boolean variable records whether the traversal is currently inside the ignored section. This technique is useful whenever the meaning of one value depends on earlier values.

The method makes its assumption executable: every starting 6 must have a later closing 7. Instead of silently ignoring the rest of an incomplete array, it throws IllegalArgumentException. If a different requirement permits incomplete sections, document and implement that policy explicitly.

Reading Array Values from Command-Line Arguments

Every command-line argument arrives as a String. Validate the required count and convert each value before processing it.

In simple terms: Validate the count before converting anything, the way a ticket collector counts the tickets before inspecting any of them. Converting first risks crashing halfway through, with the input already half processed.

public class ArgumentArray {
    public static void main(String[] args) {
        if (args.length != 5) {
            System.out.println("Usage: java ArgumentArray n1 n2 n3 n4 n5");
            return;
        }

        int[] values = new int[args.length];

        try {
            for (int index = 0; index < args.length; index++) {
                values[index] = Integer.parseInt(args[index]);
            }
        } catch (NumberFormatException exception) {
            System.out.println("Every argument must be a whole number.");
            return;
        }

        System.out.println("Greatest value: " + greatest(values));
    }

    static int greatest(int[] values) {
        int greatest = values[0];
        for (int value : values) {
            if (value > greatest) {
                greatest = value;
            }
        }
        return greatest;
    }
}

This separates input validation from the main array operation.

Building a 3 by 3 Matrix from Nine Arguments

The row and column for a flat argument index can be obtained with division and remainder.

public class MatrixMaximum {
    public static void main(String[] args) {
        if (args.length != 9) {
            System.out.println("Supply exactly nine integer values.");
            return;
        }

        int[][] matrix = new int[3][3];

        try {
            for (int index = 0; index < args.length; index++) {
                int row = index / 3;
                int column = index % 3;
                matrix[row][column] = Integer.parseInt(args[index]);
            }
        } catch (NumberFormatException exception) {
            System.out.println("All matrix values must be integers.");
            return;
        }

        int greatest = matrix[0][0];
        for (int[] row : matrix) {
            for (int value : row) {
                if (value > greatest) {
                    greatest = value;
                }
            }
        }

        System.out.println("Greatest value: " + greatest);
    }
}

Example execution:

java MatrixMaximum 8 14 3 27 5 19 4 11 6
Greatest value: 27

Matrix Addition

Two matrices can be added only when they have the same dimensions.

static int[][] add(int[][] first, int[][] second) {
    if (first.length != second.length) {
        throw new IllegalArgumentException("Row counts must match");
    }

    int[][] result = new int[first.length][];

    for (int row = 0; row < first.length; row++) {
        if (first[row].length != second[row].length) {
            throw new IllegalArgumentException("Column counts must match");
        }

        result[row] = new int[first[row].length];
        for (int column = 0; column < first[row].length; column++) {
            result[row][column] = first[row][column] + second[row][column];
        }
    }
    return result;
}

Matrix subtraction uses the same traversal with subtraction. Matrix multiplication requires the number of columns in the first matrix to equal the number of rows in the second matrix; each result cell is a sum of products.

Choosing the Correct Traversal

Requirement Traversal choice
Need the position of an element indexed for loop
Need only each value enhanced for loop
Need rows and columns nested loops
Need to stop after a match indexed loop with return or break
Need to remember whether a section is active loop with a Boolean state flag

Testing Array Algorithms

Include cases that may reveal hidden assumptions:

  • an empty array, if the method permits it;
  • one element;
  • target at the first or last position;
  • target absent;
  • duplicate values;
  • all-negative values;
  • valid and invalid command-line counts;
  • non-numeric arguments; and
  • matrix dimension mismatch.

Common Mistakes

Mistake Correction
Returning 0 when search fails Return -1, because index 0 is valid.
Starting the greatest value at 0 Start with the first element after checking that the array is not empty.
Using <= values.length Use < values.length.
Parsing arguments without checking their count Validate args.length first.
Losing track of a conditional section Use a clearly named state variable.
Silently accepting an unmatched section delimiter Validate the final state or document the intended incomplete-section policy.
Assuming all 2D rows have the same length Use matrix[row].length for each row.

Practice

  1. Return the last index of a target value, or -1 if absent.
  2. Find both the smallest and greatest values in one traversal.
  3. Count values outside every 6 to 7 section of an array.
  4. Read nine command-line values, display a 3 by 3 matrix, and print its row sums.
  5. Add and subtract two matrices after validating their dimensions.

Quick Check

1. Why does an unsuccessful linear search return -1?

Valid array indexes begin at zero, so -1 clearly indicates that no valid position was found.

2. Why should a maximum normally start with the first element?

Starting with zero gives an incorrect result when all array values are negative.

3. What does the state flag do in the conditional-sum algorithm?

It records whether the current element lies inside the section that must be ignored.

4. What type does every command-line argument initially have?

Every argument is initially a String and must be parsed before numerical operations.

Summary

Array problems become manageable when they are recognised as traversal patterns. Linear search tracks a match and its position, aggregation maintains a running result, maximum selection remembers the best value, and state flags handle context-dependent sections. Careful validation is essential when array values come from command-line input.