Dataslope logoDataslope

Basic Algorithms and Data Structures

The handful of classic patterns every programmer learns to recognize — linear and binary search, simple sorts, and the stack and queue

So far we have used data structures (lists, sets, maps) and written ad-hoc loops. This page introduces the classic algorithms and structures that show up in real software again and again. We will not get formal — no Big-O notation lectures — but we will develop intuition for which idea to reach for and why it works.

The simplest possible search: look at each element until you find what you want, or run out.

Code Block
Java 8 (Update 492)

Linear search:

  • Works on any collection — sorted, unsorted, anything iterable.
  • In the worst case, looks at every element. Doubling the collection roughly doubles the time.
  • Is exactly what List.contains(...) and List.indexOf(...) do internally for a plain ArrayList.

For small lists, this is fine. For 10 million elements, repeatedly, it is too slow. Then you need…

If the collection is sorted, you can do vastly better. Look at the middle element. If it matches, done. If your target is smaller, search the left half. Otherwise the right half. Each step eliminates half of what is left.

A list of 1 million elements is fully searched in 20 comparisons (2^20 ≈ 1M). A list of 1 billion: about 30 comparisons.

Code Block
Java 8 (Update 492)

The cost of binary search: the input must be sorted. So sorting is itself worth investing in.

A simple sort: selection sort

Sorting is one of the most-studied subjects in CS. The fancy ones (quick sort, merge sort) are clever; the slow ones are easy to understand. Here is selection sort: on each pass, find the smallest remaining element and put it in the next position.

Code Block
Java 8 (Update 492)

Selection sort takes time proportional to the square of the list length. For 10,000 elements, fine. For 10,000,000 elements, way too slow — for that you'd use the JDK's built-in Arrays.sort, which is O(n log n).

The general rule: you almost never write a sort in production Java. You call Collections.sort(list) or Arrays.sort(arr). But writing one once in your life makes the cost of sorting intuitive forever.

Two abstract data types: stack and queue

A data structure is how something is stored. An abstract data type (ADT) is what operations it supports. Two ADTs you will meet everywhere:

Stack — Last In, First Out (LIFO)

You push items on top; you pop them off the top.

Stacks model call frames (we saw it on the stack-and-heap page!), undo history, brace matching in parsers, depth-first search.

Queue — First In, First Out (FIFO)

You enqueue items at the back; you dequeue from the front. Like a line at a coffee shop.

Queues model task scheduling, message buffers, breadth-first search.

Java has classes for both — Deque (often used as a stack via ArrayDeque) and Queue (often LinkedList or ArrayDeque):

Code Block
Java 8 (Update 492)

Knowing what to reach for

A working programmer's mental table of first-resort tools:

ProblemFirst-resort tool
"Is X in this collection?"HashSet.contains
"What value goes with key K?"HashMap.get
"What's the smallest element?"sort once, take first; or use a priority queue
"Process items in arrival order"Queue
"Process items in last-in-first-out order"Deque as a stack
"Find an item in a sorted list"binary search
"Sort a list"Collections.sort
"I'll iterate a million times — does `contains` need to be fast?"use a Set, not a List

You will, of course, run into problems that don't fit this table. But this table covers an astonishing fraction of day-to-day code.

QuestionSelect one

Why does binary search require a sorted input?

Sorting makes elements take less memory

The algorithm uses the index parity

Each step compares the target to the middle element and then discards an entire half of the remaining range based on the ordering; without an ordering, you cannot rule out a half

Java's binary search throws an exception on unsorted input

QuestionSelect one

In a stack (LIFO), the last item you pushed is…

Lost forever

The next-to-last to come out

The first one to come out when you pop

Sorted to the bottom

QuestionSelect one

A program calls list.contains(x) inside a tight loop 1,000,000 times on a 1,000,000-element ArrayList. Which change is most likely to fix the resulting slowness?

Replace the loop with recursion

Sort the list first and keep using contains

Replace the ArrayList with a HashSet so each contains call runs in roughly constant time

Re-create the list with a smaller capacity

A challenge

Challenge
Java 8 (Update 492)
Reverse a string with a stack

Implement Reverser.reverse(String s) using a Deque<Character> as a stack: push every character, then pop them all back into a StringBuilder.

Main.java is provided. Expected output (exact):

!olleh

You now have a vocabulary for the dozen most common patterns. The last conceptual page widens the lens one more time: how is a whole program organized?

On this page