Warm-up

Time the two lists yourself

5 minfresher04 yrs

One concept, guided. Near-impossible to fail.

What this teaches

  • Random access on a LinkedList walks the chain, so it is orders slower
  • Iteration with for-each is a draw; index loops over LinkedList are O(n^2)
  • Mid-list insertion goes to ArrayList, against the folklore
  • LinkedList wins only at the head

Starter

Starter.java
import java.util.*;

/**
 * Warm-up: measure, don't recite.
 *
 * Before you run this, write down which list you expect to win each of the four
 * operations. The exercise is worthless if you skip that step — the point is to
 * be wrong on paper, once, so you remember it.
 */
public class Starter {

    static final int N = 50_000;
    static final int INSERTS = 10_000;

    static long ms(Runnable r) {
        long start = System.nanoTime();
        r.run();
        return (System.nanoTime() - start) / 1_000_000;
    }

    static void sink(long v) {
        if (v == Long.MIN_VALUE) System.out.print("");
    }

    static void bench(String label, List<Integer> list) {
        for (int i = 0; i < N; i++) list.add(i);

        Random rnd = new Random(42);
        int[] idx = new int[5_000];
        for (int i = 0; i < idx.length; i++) idx[i] = rnd.nextInt(N);

        long get = ms(() -> { long s = 0; for (int i : idx) s += list.get(i); sink(s); });
        long iterate = ms(() -> { long s = 0; for (int v : list) s += v; sink(s); });
        long middle = ms(() -> { for (int i = 0; i < INSERTS; i++) list.add(list.size() / 2, i); });
        long head = ms(() -> { for (int i = 0; i < INSERTS; i++) list.add(0, i); });

        System.out.printf("%-11s get=%dms iterate=%dms insert-mid=%dms insert-head=%dms%n",
            label, get, iterate, middle, head);
    }

    public static void main(String[] args) {
        // Untimed pass so the JIT has compiled the loops before we measure.
        bench("(warmup)", new ArrayList<>());
        bench("(warmup)", new LinkedList<>());

        System.out.println("--- measured ---");
        bench("ArrayList", new ArrayList<>());
        bench("LinkedList", new LinkedList<>());

        // TODO 1: which result differs most from what you predicted?

        // TODO 2: add a fifth measurement — an INDEX loop:
        //     for (int i = 0; i < list.size(); i++) sum += list.get(i);
        // Run it on both. Start with N = 50_000 and be ready to wait.
        // Then explain why it is not the same as the for-each iterate result.

        // TODO 3: add ArrayDeque to the head-insertion comparison. It is not a
        // List, so you will need a Deque variable. Does it beat LinkedList?
    }
}

Run it locally:

cd exercises/java/collections/arraylist-vs-linkedlist/01-warmup
javac Starter.java -d /tmp/out && java -cp /tmp/out Starter

Done when

  • You wrote your prediction down before running it
  • You can say which of the four results surprised you and why
  • You changed the index loop to for-each and saw the difference

← Back to When would you use LinkedList instead of ArrayList?