AP COMPUTER SCIENCE A • DATA COLLECTIONS

Implementing ArrayList Algorithms

Master traversal, insertion, removal, and search patterns that form the backbone of dynamic list processing in Java.

Historical Context & Motivation

Before languages offered built-in resizable collections, programmers managed dynamic data by manually allocating arrays, copying elements, and tracking size counters—a tedious and error-prone process. The need for algorithmic patterns over dynamic lists became apparent as software systems grew beyond trivial data sizes. Java's introduction of the ArrayList class in the Collections Framework (Java 1.2, 1998) gave developers a standard abstraction that handles resizing internally, but the responsibility for writing correct traversal, insertion, removal, and search algorithms still falls squarely on the programmer.

1960s
Early List Processing
Languages like LISP pioneer linked-list abstractions; arrays remain the dominant random-access structure in imperative languages like FORTRAN and C.
1995
Java 1.0 & the Vector Class
Java ships with the synchronized Vector class—a resizable array—but its thread-safe overhead proves costly for single-threaded algorithms.
1998
Java 1.2 Collections Framework
The ArrayList class debuts as an unsynchronized, high-performance resizable array implementing the List interface, becoming the standard for AP CS A.
2004
Generics in Java 5
Parameterized types (e.g., ArrayList<String>) eliminate unsafe casts, making list algorithms type-safe at compile time.
2020s
AP CS A Curriculum Emphasis
The College Board centers ArrayList algorithms in Unit 7, requiring students to implement traversals, insertions, and removals using both indexed and enhanced for loops.

The central question this lesson addresses is: given a dynamically sized list of objects, how do you correctly and efficiently traverse, search, filter, and transform that list without introducing off-by-one errors, skipping elements during removal, or causing ConcurrentModificationException? These are the exact pitfalls that the AP exam tests repeatedly.

Core Principles & Definitions

An ArrayList is a generic, resizable-array implementation of the List interface. Unlike a primitive array whose length is fixed at construction, an ArrayList grows and shrinks as elements are added or removed. All ArrayList algorithms on the AP exam rely on a small set of methods: size(), get(int index), set(int index, E element), add(E element), add(int index, E element), and remove(int index).

1

Indexed Traversal

Use a standard for loop with an index variable. Required when you need to add or remove elements during iteration, because the index can be adjusted to compensate for shifts.
2

Enhanced For-Each Traversal

The for (Type elem : list) loop reads every element without exposing the index. It is concise but must not be used when the list's size changes during iteration.
3

Insertion & Shifting

Calling add(i, elem) shifts every element at index i and above one position to the right, increasing size by 1. This is O(n) in the worst case.
4

Removal & Index Adjustment

Calling remove(i) shifts elements left and decreases size by 1. If you advance the index after removal, you skip the element that shifted into position i.
5

Linear Search

Traverse the list comparing each element to a target. Return the index on match or −1 if not found. The average case inspects n/2 elements.
KEY TAKEAWAY
Think of an ArrayList like a row of chairs in a theater. Adding a chair in the middle forces everyone to the right to scoot over; removing one lets everyone shift left. If you are walking down the row counting people (traversing) and someone removes a chair right behind you, you will accidentally skip a seat unless you step back one position—this is exactly why indexed removal requires an index adjustment.

Visual Explanation — Traversal & Removal

The top half shows the classic bug: incrementing i after a removal causes the second "B" to shift into position 1, but i has already advanced to 2, skipping it. The bottom half shows the correct fix—only increment i in the else branch, or traverse backwards.

This diagram illustrates the single most common ArrayList bug tested on the AP exam. When you call remove(i), every element to the right of index i shifts one position to the left, and size() decreases by one. If your loop blindly increments i after the removal, the element that just shifted into position i is never inspected. Two canonical fixes exist: use a conditional increment (only advance i when no removal occurs), or traverse the list backwards so that shifts affect only indices you have already visited.

How ArrayList Operations Work Internally

Although the AP exam does not require you to implement ArrayList itself, understanding the internal mechanics deepens your grasp of why certain algorithms are efficient and others are not. Internally, an ArrayList wraps a plain Object[] array and maintains an integer size field. When add() is called and the backing array is full, the ArrayList allocates a new array (typically 1.5× the old capacity), copies all elements, and then inserts the new element.

Time Complexity of Key Operations

INDEXED ACCESS
get(i) → O(1)
Direct array indexing; constant time regardless of list size.
APPEND TO END
add(elem) → amortized O(1)
Usually O(1); occasionally O(n) when resizing is triggered, but amortized over many calls it averages to constant time.
INSERT AT INDEX / REMOVE AT INDEX
add(i, elem) or remove(i) → O(n)
Elements from index i to size−1 must be shifted right (for insert) or left (for remove). Worst case shifts all n elements.
LINEAR SEARCH
Sequential scan → O(n)
Must inspect each element in the worst case. On average, n/2 comparisons.
💡 AP Exam Tip
The AP exam will not ask you to state Big-O notation explicitly, but free-response graders expect efficient solutions. Avoid nested loops over the same list unless the problem specifically requires comparing all pairs—an O(n²) approach when O(n) suffices will lose style points or lead to incorrect logic.

Common Algorithm Patterns

The AP CS A exam recycles a small set of algorithmic patterns that can be combined to solve virtually any ArrayList free-response question. Mastering these patterns transforms unfamiliar problems into straightforward template applications.

Six fundamental ArrayList algorithm patterns with code templates. The top row covers read-only and destructive traversals; the bottom row covers insertion and pair comparison. Note how each pattern dictates the loop structure and index management strategy.
Summary of loop and index strategies for each pattern
PatternLoop TypeIndex AdjustmentModifies Size?
Accumulate (sum, max, count)for-each or indexedStandard i++No
Linear searchIndexedStandard i++; return on matchNo
Remove all matchingIndexed (backward preferred)Backward: i−−; Forward: conditional i++Yes ↓
Insert after matchingIndexed forwardAfter insert: i += 2 to skip inserted elementYes ↑
Consecutive pairsIndexed to size()−1Standard i++; bound is size()−1No

Worked Example — Removing Duplicates

Write a method removeDuplicates that takes an ArrayList<String> and removes all duplicate occurrences so that only the first occurrence of each string remains. For example, ["a", "b", "a", "c", "b"] becomes ["a", "b", "c"].

Removing Duplicates from an ArrayList<String>
1
Step 1 — Choose a traversal strategyBecause we will be calling remove() during traversal, we must use an indexed for loop. A forward traversal with conditional increment works well here: for each element, scan the remainder of the list for duplicates and remove them.
2
Step 2 — Outer loop iterates through each elementfor (int i = 0; i < list.size(); i++) — this advances normally because we never remove the element at index i itself, only elements after it.
3
Step 3 — Inner loop removes later duplicatesFor each i, start j = i + 1 and scan forward. If list.get(j).equals(list.get(i)), call list.remove(j) and do NOT increment j. Otherwise, increment j.
4
Step 4 — Write the complete methodpublic static void removeDuplicates(ArrayList<String> list) { for (int i = 0; i < list.size(); i++) { int j = i + 1; while (j < list.size()) { if (list.get(j).equals(list.get(i))) { list.remove(j); } else { j++; } } } }
Input: ["a", "b", "a", "c", "b"] → Output: ["a", "b", "c"]. The while loop re-evaluates list.size() each iteration, so shrinking the list is handled correctly.
5
Step 5 — Trace through the examplei=0 ("a"): j scans and removes index 2 ("a"). List becomes ["a","b","c","b"]. i=1 ("b"): j scans and removes index 3 ("b"). List becomes ["a","b","c"]. i=2 ("c"): no duplicates found. Loop ends.
Final list: ["a", "b", "c"]

ArrayList vs. Array — Strengths & Limitations

The AP exam expects you to choose between arrays and ArrayLists based on the problem requirements. Understanding the trade-offs between these two data structures is essential for both the multiple-choice and free-response sections.

Key differences between arrays and ArrayLists on the AP exam
FeatureArrayArrayList
SizeFixed at creationDynamic; grows/shrinks automatically
PrimitivesStores primitives directly (int, double)Wrapper classes only (Integer, Double)
Access syntaxarr[i]list.get(i)
Insert/remove in middleManual shifting requiredBuilt-in add(i, e) / remove(i)
Length / size.length (field).size() (method)
Ideal whenSize is known and fixed; primitives neededSize varies; frequent insertion/removal
KEY TAKEAWAY
Arrays are like fixed-size toolboxes: fast and lightweight, but you cannot add a slot. ArrayLists are like expandable accordion folders: they adapt to however many documents you insert, but each document must be wrapped in an envelope (autoboxing). Choose the structure that matches your problem's mutability requirements.

Connection to Advanced Data Structures

The ArrayList algorithms you learn in AP CS A are foundational patterns that reappear throughout computer science. In a data structures course, you will encounter LinkedLists, where insertion and removal at arbitrary positions become O(1) once you have a reference to the node, but random access degrades to O(n). The traversal patterns—forward iteration, conditional removal, accumulation—transfer directly, though the implementation uses node pointers instead of integer indices.

How AP-level ArrayList concepts connect to more advanced topics
ConceptAP CS A (ArrayList)Beyond AP (Advanced)
TraversalIndexed for-loop, for-eachIterators, streams, recursive traversal
Removal during iterationBackward loop or conditional i++Iterator.remove(), removeIf()
SearchLinear scan O(n)Binary search O(log n), hash lookup O(1)
SortingSelection/insertion sortMerge sort, quicksort, Collections.sort()
Type safetyGenerics (ArrayList<E>)Bounded wildcards, covariance

Understanding why remove() shifts elements and how that affects your loop index prepares you to reason about more complex data structure invariants in courses on algorithms and systems programming. The discipline of asking "does my loop variable still point to the right element after a mutation?" is the same discipline that prevents bugs in concurrent programming, database cursor management, and network packet processing.

Practice Problems

1
Consider the following code segment: ArrayList<String> list = new ArrayList<>(Arrays.asList("A", "B", "B", "C")); for (String s : list) { if (s.equals("B")) { list.remove(s); } } What happens when this code executes? A. The list becomes ["A", "C"] with both "B" elements removed. B. The list becomes ["A", "B", "C"] with only the first "B" removed. C. A ConcurrentModificationException is thrown. D. An IndexOutOfBoundsException is thrown.
2
What is the value of result after the following code executes? ArrayList<Integer> nums = new ArrayList<>(Arrays.asList(3, 7, 2, 8, 5)); int result = 0; for (int n : nums) { if (n > 4) { result += n; } } A. 25 B. 20 C. 15 D. 5
3
Consider the following method: public static void mystery(ArrayList<Integer> list) { for (int i = list.size() - 1; i > 0; i--) { if (list.get(i) < list.get(i - 1)) { list.add(i, list.remove(i - 1)); } } } If list is initially [5, 3, 8, 1], what is list after calling mystery(list)? A. [1, 3, 5, 8] B. [3, 5, 1, 8] C. [1, 5, 3, 8] D. [5, 3, 1, 8]
PROBLEM 4APPLIED
A teacher stores student scores in an ArrayList<Integer> called scores. Write a method public static ArrayList<Integer> aboveAverage(ArrayList<Integer> scores) that returns a new ArrayList containing only the scores that are strictly above the average of all scores. Do not modify the original list. Assume scores is non-empty and contains at least one element.
PROBLEM 5CRITICAL THINKING
Write a method public static void removeSandwich(ArrayList<String> list, String start, String end) that removes all elements between the first occurrence of start and the first occurrence of end that appears after start, exclusive (i.e., keep both start and end in the list but remove everything between them). If start or end is not found (or end does not appear after start), do nothing.

Summary — Implementing ArrayList Algorithms

ArrayList algorithms on the AP CS A exam revolve around a small set of repeatable patterns. Traversal can use either an indexed for-loop or a for-each loop, but you must use the indexed form whenever insertion or removal changes the list's size during iteration. The cardinal rule for removal during forward traversal is to avoid incrementing the index after a remove—or equivalently, traverse backwards. For insertion during traversal, increment the index by 2 to skip the newly inserted element.

Common patterns include accumulation (sum, count, min, max), linear search (return index or −1), filtering (remove elements matching a condition), and consecutive pair comparison (loop bound is size() - 1). Each pattern dictates a specific loop structure and index management strategy. Mastering these six templates equips you to decompose any FRQ into familiar building blocks.

Varsity Tutors • AP Computer Science A • Implementing ArrayList Algorithms