Maps — Key-Value Storage

CS205 Data Structures

Use arrow keys or buttons to navigate

What is a Map?

A map (dictionary / associative array) stores (key, value) pairs. Each key maps to exactly one value. Keys must be unique.

Real-World Analogies

  • Dictionary: word → definition
  • Phone book: name → phone number
  • Student ID: ID → student record
  • DNS: domain name → IP address

Core Insight

A map is about lookup by key. You don't ask "what's at position 3?" — you ask "what is the value for key "banana"?"

The Map ADT

The abstract interface any map implementation must support:

Core Operations

V get(K key)
// value for key, or null
V put(K key, V value)
// insert or update; returns old value
V remove(K key)
// remove entry; returns old value
boolean containsKey(K key)
int size()
boolean isEmpty()

Collection Views

Set<K> keySet()
Collection<V> values()
Set<Entry<K,V>> entrySet()

Interactive Trace

Keys Must Be Unique

put("apple",5) then put("apple",9) → only one "apple" entry with value 9. The old value 5 is replaced.

Map vs Set vs List

Three fundamental collection types — each organizes data differently.

FeatureListSetMap
Access byIndexMembershipKey
DuplicatesAllowedNoKeys unique
OrderYesDependsDepends
Use whenOrdered seq.UniquenessKey lookup

Which would you use?

Quick Decision Guide

Need to find items by position? → List. Need to check membership? → Set. Need to look up value by key? → Map.

Implementation 1: Unsorted List

Store entries in an unordered list — simple but slow

OperationTimeWhy?
get(k)O(n)Linear scan
put(k,v)O(n)Search first
remove(k)O(n)Linear scan

Why O(n) for Everything?

Without ordering, finding a key requires checking every entry. Even put() must search first to check if the key already exists.

When Is This OK?

For very small maps (< 20 entries), the simplicity and cache-friendliness outweigh the O(n) cost.

Implementation 2: Sorted Array

Keep entries sorted by key — binary search for O(log n) lookups

OperationTime
get(k)O(log n)
put(k,v) existingO(log n)
put(k,v) newO(n)
remove(k)O(n)

Binary Search Wins for Lookups

Finding a key is O(log n) — much better! But inserting a new key still needs shifting to maintain sorted order → O(n).

The Shifting Problem

To insert "cow" between "cat" and "dog", we must shift "dog" and "fish" right. Same shifting cost as ArrayList insertion.

Multimap

A variation where one key maps to multiple values

Simulating with Map<K, List<V>>

Map<String, List<String>> courses
= new HashMap<>();
// Add a course for Alice
courses.computeIfAbsent("Alice",
k -> new ArrayList<>()).add("CS");
courses.computeIfAbsent("Alice",
k -> new ArrayList<>()).add("Math");
// Get all of Alice's courses
courses.get("Alice");
// → ["CS", "Math"]

When to Use

One-to-many: student → courses, word → positions in text, vertex → neighbors (adjacency list).

put() Operation — Step by Step

Two cases: update existing key, or insert new entry

public V put(K key, V value) {
// Step 1: Search for existing key
for (Entry e : entries) {
if (e.key.equals(key)) {
V old = e.value;
e.value = value; // update
return old;
}
}
// Step 2: Not found, insert new
entries.add(new Entry(key,value));
size++;
return null;
}

put() Always Searches First

Even for insertion, put() must scan all entries to check if the key exists. This is why put() in an unsorted list is O(n), not O(1).

Return value: old value (update) or null (insert).

get() Operation

Search for a key and return its value, or null if absent

public V get(K key) {
for (Entry e : entries) {
if (e.key.equals(key)) {
return e.value; // found!
}
}
return null; // not in map
}

null Can Be Ambiguous

If get("grape") returns null — is the key absent, or does it exist with a null value? Use containsKey() to disambiguate:

if (map.containsKey("grape")) {
// key exists, value might be null
} else {
// key truly absent
}

remove() Operation

Find entry by key, remove it, return old value

public V remove(K key) {
for (int i = 0; i < size; i++) {
if (entries[i].key.equals(key)) {
V old = entries[i].value;
// Swap with last entry
entries[i] = entries[size-1];
entries[size-1] = null;
size--;
return old;
}
}
return null;
}

Swap-with-Last Trick

Since unsorted list has no required order, replace the removed entry with the last in O(1). Search is still O(n), but the removal step itself is O(1).

Does NOT work for sorted arrays — swapping breaks sorted order.

Ordered Map / Sorted Map

Keys in sorted order — enables range queries and ordered traversal

Why Maintain Sorted Order?

  • Range queries: "all entries between 'C' and 'M'"
  • Ordered iteration: smallest to largest
  • Min/max: find smallest/largest key in O(log n)
  • Floor/ceiling: nearest key to a value

Filing Cabinet Analogy

Unsorted map = tossing files in a box — fast to add, slow to find. Sorted map = alphabetized filing cabinet — slightly slower to insert, but fast lookup and browsing.

Requirement

Keys must implement Comparable or you must provide a Comparator.

Implementation Preview: What's Coming

Two powerful map implementations ahead

Hash Table

The Dream: O(1) Average

Compute index directly from key via hash function. No search needed! Trade-off: no ordering, O(n) worst case from collisions.

Binary Search Tree

Best of Both Worlds

O(log n) for all operations AND sorted order. Java's TreeMap = Red-Black BST.

Implementationget()put()remove()Ordered?
Unsorted ListO(n)O(n)O(n)No
Sorted ArrayO(log n)O(n)O(n)Yes
Hash TableO(1) avgO(1) avgO(1) avgNo
Balanced BSTO(log n)O(log n)O(log n)Yes

Application: Word Frequency Counter

Count occurrences of each word — a classic map use case

Map<String, Integer> freq
= new HashMap<>();
for (String word : words) {
if (freq.containsKey(word)) {
freq.put(word,
freq.get(word) + 1);
} else {
freq.put(word, 1);
}
}
// Cleaner:
freq.put(word,
freq.getOrDefault(word,0)+1);

Tally Sheet

New word? Add a row with count 1. Seen again? Add a tally mark. The map is the tally sheet.

Challenge: Trace Map Operations

Predict the return values and final map state

Starting with an empty map, execute:

1. put("x", 1) → returns
2. put("y", 2) → returns
3. put("x", 3) → returns
4. get("y") → returns
5. remove("y") → returns
6. get("y") → returns
7. size() → returns

Application: Two-Sum Problem

Find two numbers that add to a target — O(n) with a map

Map<Integer,Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (seen.containsKey(complement)) {
return new int[]{
seen.get(complement), i };
}
seen.put(nums[i], i);
}

The Key Insight

Store each number in a map as you go. For each new number, compute its complement (target − num) and check if it's already in the map. One pass = O(n) vs O(n²) brute force.

Dance Partner

People enter a room one at a time, each with a number. Each asks: "Is someone here whose number + mine = target?" If yes — pair found! The map is the room's registry.

Challenge: Fix the Bug

This word frequency counter has a subtle error

Map<String, Integer> freq
= new HashMap<>();
String[] words = text.split(" ");
for (String word : words) {
freq.put(word, freq.get(word) + 1);
}

What happens when this code runs on "the cat the"?

Java's Map Interface

HashMap, TreeMap, LinkedHashMap — different trade-offs

ImplOrderOpsnull keys?
HashMapNoneO(1) avgYes (1)
TreeMapSortedO(log n)No
LinkedHashMapInsertionO(1) avgYes (1)
// HashMap — most common
Map<String, Integer> map
= new HashMap<>();
map.put("apple", 3);
map.put("banana", 7);
map.get("apple"); // 3
// Iterate entries
for (Map.Entry<String, Integer> e
: map.entrySet()) {
e.getKey(); // "apple"
e.getValue(); // 3
}

Decision Flowchart

Fastest lookups? → HashMap
Sorted keys / ranges? → TreeMap
Insertion order (LRU cache)? → LinkedHashMap

Common Mistake

HashMap iteration order is unpredictable and changes when entries are added/removed.

Challenge: Choose the Right Map

HashMap, TreeMap, or LinkedHashMap?

1. Count word frequencies in a large text file as fast as possible.

2. Store user settings and write them to a config file in the order they were added.

3. Implement an address book where contacts are always displayed alphabetically.

4. Find all students with IDs between 1000 and 2000.

Summary & Cheat Sheet

Everything you need to know about maps in one slide

Core Operations

get(key) → value or null
put(key, val) → old value or null
remove(key) → old value or null
containsKey(k) → boolean
keySet() / values() / entrySet()

When to Use a Map

  • Look up values by key (not by index)
  • Count occurrences (word frequency)
  • Associate data (student ID → record)
  • Check existence quickly
  • Two-sum style complement lookups

The Big Picture

Lists are about ordering. Sets are about uniqueness. Maps are about association — connecting a key to its value. Maps are arguably the most widely used data structure in real-world programming.

Coming Next

Hash Tables — how to achieve O(1) average using hash functions and buckets.

Quiz: Test Your Map Knowledge

3 questions — pick the best answer

Q1: What does put("x",5) return if "x" already has value 3?

Q2: Why is put() O(n) in an unsorted list map?

Q3: Which Java Map preserves insertion order?

Quiz: Trace This Code

What is printed?

Map<String, Integer> m = new HashMap<>();
m.put("a", 1);
m.put("b", 2);
m.put("c", 3);
m.put("a", 4);
System.out.println(m.size());
System.out.println(m.get("a"));
System.out.println(m.remove("b"));
System.out.println(m.get("b"));
System.out.println(m.size());

Enter the 5 printed values (one per line):

Quiz: Two-Sum Challenge

Apply the map-based two-sum pattern

Given nums = [3, 1, 4, 1, 5, 9] and target = 10, trace the map-based two-sum algorithm.

At which index do we find the solution?

(i.e., what value of i triggers the "found" branch?)