Hook: TreeMap is like a library shelf that stays alphabetically sorted while you keep adding books—interviewers love it because it tests both sorted collections and tree internals.
Question: What is the internal working of TreeMap in Java?
Answer: TreeMap stores entries in sorted key order using a red-black tree, which is a self-balancing binary search tree. That means search, insert, and delete usually take O(log n) time. It keeps keys ordered by either a supplied Comparator or the keys’ natural ordering, and it also supports fast navigation like firstKey(), ceilingKey(), and range views such as subMap().
Interview-Ready Answer: I’d say TreeMap is a sorted map backed by a red-black tree. Each operation compares keys step by step down the tree, then may rebalance with recoloring and rotations, so get, put, and remove are O(log n). The big idea is that ordering is based on a comparator or natural order, and that also means equality is decided by comparison result 0, not by equals().
Detailed Explanation: TreeMap is Java’s sorted map implementation. A map stores key -> value pairs, and TreeMap keeps the keys in sorted order at all times. Under the hood, it uses a red-black tree, which is a binary search tree that stays balanced by using node colors and a few local fixes after updates.
Comparator, TreeMap uses it. If not, it expects keys to implement Comparable and uses natural ordering.compare(...) == 0), the old value is replaced. This is a key gotcha: TreeMap uses ordering, not equals(), to decide key uniqueness.A red-black tree keeps its height small. In practice, the height is bounded to about 2 * log2(n + 1), so even with 1,000,000 entries, the tree height stays around 40 or less. That is why TreeMap remains predictable under load.
Use TreeMap when you need sorted keys, range queries, or the nearest key before/after a target. Examples: scheduling, leaderboards by score, time-based lookups, and building views like headMap, tailMap, and subMap.
Do not choose it just for faster raw lookup. A hash-based map is usually faster for plain key lookup if you do not need ordering.
| Map | Order | Typical Ops | Best For |
|---|---|---|---|
| TreeMap | Sorted | O(log n) | Range queries |
| HashMap | None | O(1) avg | Fast lookup |
| LinkedHashMap | Insertion/access | O(1) avg | Stable iteration |
Memory and edge cases: each TreeMap node stores extra pointers for parent, left, and right, plus a color flag. So it uses more memory than HashMap. Also, natural-order TreeMap does not allow null keys because it must compare keys; a custom comparator can allow null if it is written to handle it.
subMap(), headMap(), and tailMap() return backed views, meaning they are not copies. A change in the view changes the original map, and a valid change in the original map can appear in the view. Getting the starting point costs O(log n); iterating over the returned range is linear in the number of items returned.
get, put, remove: O(log n)firstKey, lastKey, floorKey, ceilingKey: O(log n)O(n)O(log n + k), where k is the number of returned entriesMemory hook: think of TreeMap as a sorted hallway with checkpoints: every key walks left or right, then the tree does a few quick posture fixes so the hallway never becomes a long, slow corridor.
Real-World Example: In a checkout service, you might store discount rules by minimum cart value: 100 -> 5%, 200 -> 10%, 500 -> 20%. When a user checks out with 275, the system can use floorEntry(275) to find the best applicable discount quickly.
What goes wrong when the team misunderstands TreeMap? A developer uses a comparator that compares only by minute of the day, so two promotions starting at 10:15 and 10:15 are treated as the same key. One rule silently overwrites the other, causing some customers to get the wrong discount. In logs, the map size is smaller than the config file, and support sees complaints like 'promo not applied' even though the rule exists in source control.
That bug is painful because nothing crashes. TreeMap is doing exactly what it was told: if comparison says two keys are equal, only one entry can live there.
import java.util.Comparator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
// Natural ordering: keys are kept sorted automatically.
TreeMap<Integer, String> prices = new TreeMap<>();
prices.put(40, "Silver");
prices.put(10, "Bronze");
prices.put(30, "Gold");
prices.put(20, "Starter");
System.out.println("All entries in sorted order:");
for (Map.Entry<Integer, String> e : prices.entrySet()) {
System.out.println(e.getKey() + " -> " + e.getValue());
}
// Navigation methods are why TreeMap is useful for range queries.
System.out.println("firstKey = " + prices.firstKey());
System.out.println("lastKey = " + prices.lastKey());
System.out.println("floorKey(25) = " + prices.floorKey(25));
System.out.println("ceilingKey(25) = " + prices.ceilingKey(25));
// subMap is a backed view, not a copy.
NavigableMap<Integer, String> midRange = prices.subMap(15, true, 35, true);
System.out.println("subMap(15..35) = " + midRange);
// Removing the smallest item shows that TreeMap can efficiently expose extremes.
System.out.println("pollFirstEntry = " + prices.pollFirstEntry());
System.out.println("After pollFirstEntry = " + prices);
// Edge case: natural-order TreeMap rejects null keys because it must compare them.
try {
prices.put(null, "BadKey");
} catch (NullPointerException ex) {
System.out.println("Null key with natural ordering throws: " + ex.getClass().getSimpleName());
}
// A custom comparator can choose to support null keys if it handles them explicitly.
TreeMap<Integer, String> nullFriendly = new TreeMap<>(Comparator.nullsFirst(Comparator.naturalOrder()));
nullFriendly.put(null, "Unknown");
nullFriendly.put(2, "Two");
nullFriendly.put(1, "One");
System.out.println("Null-friendly TreeMap = " + nullFriendly);
// The key lesson: ordering, not equals(), decides uniqueness.
TreeMap<String, Integer> caseInsensitive = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
caseInsensitive.put("Java", 1);
caseInsensitive.put("JAVA", 2); // overwrites because compare(...) returns 0
System.out.println("Case-insensitive map = " + caseInsensitive);
}
}Follow-up & Tricky Questions:
O(log n) operations, while HashMap gives average O(1) operations but no order.subMap, headMap, and tailMap copies? No, they are backed views. Updating the view updates the original TreeMap, and vice versa if the change stays within the view’s range.equals() to find duplicate keys? No, it uses comparison. If compare(a, b) == 0, TreeMap treats them as the same key even when equals() says they are different.ConcurrentSkipListMap.O(log n) per entry? No. Walking through entries is linear overall; the tree is already ordered, so iteration just follows links in sequence.put replaces the earlier value.Common Mistakes:
equals() for keys. Correction: key uniqueness is based on comparison result 0, not equals().Memory Hook: Picture a balanced search tree librarian: every book is placed by alphabet, and after each new book the librarian straightens the shelf so it never leans too far left or right.
Cheat Sheet:
Map backed by a red-black tree.get, put, remove are O(log n).0 means same key.floor, ceiling, and range views.Practice Tasks:
subMap view and verify that removing from the view changes the original map.