Linear Search Versus Tree Search
Second, a linear search, which checks entries one after another from the beginning, is inefficient for all but the shortest lists.
Searching a Plain List of Pairs
Suppose you keep a list of people and their phone numbers, where each entry is a pair holding a name and a number. When you want the number for one particular name, you have to walk through the list and compare names until you find a match. For a short list this is perfectly fine. For a long list it becomes slow, and writing the search code over and over becomes tedious. The question this article answers is whether there is a container designed so that finding a value by its name is the natural operation, not an afterthought.
Two observations set up the rest of the topic. First, writing code to look up a name in a list of name-number pairs is quite tedious. Second, a linear search, which checks entries one after another from the beginning, is inefficient for all but the shortest lists. The standard library responds to this problem by offering a search tree called map.
How a Linear Search Walks the List
A linear search starts at the first entry and compares it with the name you want. If it matches, the search stops and returns that entry. If it does not match, the search moves to the next entry and repeats the comparison. The search stops either when a match is found or when the list runs out of entries. Nothing about the list's arrangement helps it skip ahead, so in the worst case every entry must be examined.
The diagram uses five invented name-number pairs in alphabetical order. Even with the list sorted, a linear search does not exploit that order. It checks Alice, then Bob, then Dana, then Eve, and only stops once it reaches the match. Sorting alone does not change the procedure; the search still reads entries one at a time from the beginning.
What a Map Is
A map is a container of pairs of values optimized for lookup, so it suits problems where finding a value by its key is the main task.
The word container matters here. Like the other standard containers, a map holds a collection of items, and you create it, fill it, and query it. What sets a map apart is its purpose. A vector or a list is organized around positions in a sequence, while a map is organized around the pairs it stores so that a lookup can be performed efficiently. The map is optimized for lookup, which is the reason to choose it over a plain sequence when you frequently need to find values.
Creating a map looks familiar if you already know vectors and lists, because the same initializer style applies. You list starting values in braces, just as you would for a vector or a list, so the new container is easy to begin using. Familiar syntax should not hide the difference in purpose, however. The initializer tells you how to fill the container; the optimization for lookup tells you why you would choose a map in the first place.
Use a map when the central question is which value belongs to a given key. Use a plain sequence when the central question is what sits at a given position.
Three Names for One Container
The same container goes by different names in different contexts. Outside the standard library's own vocabulary, a map is known as an associative array or a dictionary. When you read documentation or discussions in other languages and tools, you may see any of these three names, and they all refer to a collection of pairs in which you look up one value by means of another.
Map is the name used by the standard library, while associative array and dictionary are names you will meet elsewhere. Which one a discussion uses depends on the context, but the underlying idea of a collection of pairs searched by one part of each pair is the same.
Arranging Pairs as a Search Tree
The reason a map can answer lookups quickly is its internal arrangement. The standard-library map is implemented as a balanced binary tree, which is a search tree designed to keep lookups efficient. Instead of a flat list that is scanned from the front, the pairs are stored in a branching structure whose shape is chosen so that searching for a key follows a short path.
Tracing a Linear Search for Eve
Finding Eve's number by scanning the list
Five invented name-number pairs are stored as a plain alphabetical list: Alice 555-0101, Bob 555-0102, Dana 555-0104, Eve 555-0105, Frank 555-0106. Find the number for Eve using a linear search.
- 1Check the first entry
Compare Eve with Alice. No match, so move on to the next entry.
- 2Check the second entry
Compare Eve with Bob. No match, so move on.
- 3Check the third entry
Compare Eve with Dana. No match, so move on.
- 4Check the fourth entry
Compare Eve with Eve. Match found, so the search stops and returns 555-0105.
Four comparisons were needed. Frank was never examined, and the list's alphabetical order did not reduce the work.
What do you think happens?
Using the same five pairs in a plain list, how many entries does a linear search compare before it finds Eve?
Reveal answer
4
The search compares Alice, Bob, Dana, and then Eve. It must reach the fourth entry before the match is found.
Tracing a Tree Search for Eve
Finding Eve's number in the search tree
The same five pairs are arranged as a balanced binary tree with Dana at the root, Bob and Frank as its children, Alice under Bob, and Eve as the left child of Frank. Find the number for Eve.
- 1Compare at the root
Eve sorts after Dana, so the search goes into the right branch and ignores Alice and Bob entirely.
- 2Compare at Frank
Eve sorts before Frank, so the search goes into the left branch of Frank.
- 3Reach Eve
The entry at this node is Eve, so the search returns 555-0105.
Three comparisons were needed, and the search never looked at Alice or Bob. Each comparison ruled out an entire branch of the tree.
Comparing the Two Search Strategies
| Feature | Plain list of pairs with linear search | Map as a balanced binary tree |
|---|---|---|
| Organization | Entries kept in a sequence, read from the front | Pairs arranged in a branching structure ordered by key |
| How a lookup proceeds | Compares entries one after another until a match | Compares at each node and moves to the left or right subtree |
| Work for a long list | Can require examining every entry | Follows a short path from the root because the tree is balanced |
| Code to write for lookup | A search loop written again for each use | A lookup operation provided by the container |
| Best suited to | Short lists, or tasks needing position order | Problems where finding a value by its key is the main task |
Linear search over a plain list compared with lookup in a map
Mistakes Learners Make With Maps
Common mistake Assuming a map is just a list with a different syntax
What it looks likeCreating a map with the same braces as a vector and then looking up values by position as if it were a sequence.
Why it failsThe initializer style is shared, but the map is organized around its key-value pairs for lookup, not around positions in a sequence.
Do this insteadUse a map when you need to find a value from its key, and use a sequence when position is what matters.
Common mistake Thinking a sorted plain list is as fast as a map
What it looks likeKeeping names in alphabetical order in a vector and still scanning from the first entry for every lookup.
Why it failsA linear search checks entries one at a time from the beginning, so sorting alone does not change how many entries are examined.
Do this insteadIf lookups by key are frequent, store the pairs in a map whose tree arrangement guides the search.
Common mistake Treating dictionary and map as different kinds of container
What it looks likeReading that a dictionary stores pairs and then assuming it must work differently from a standard-library map.
Why it failsAssociative array, dictionary, and map are different names for the same kind of container in different contexts.
Do this insteadWhen you see any of the three names, expect a collection of pairs looked up by one part of each pair.
Common mistake Forgetting that a balanced tree is needed for the short path to hold
Practice Tracing Both Searches
Using the same five pairs (Alice, Bob, Dana, Eve, Frank) and the tree with Dana at the root, trace a lookup for Frank in the plain list and then in the tree. Count the comparisons each method makes and explain which entries the tree search skipped.
Hints
- In the plain list, Frank is the last entry, so think about how many entries come before it.
- In the tree, compare Frank with the root first and decide whether to go left or right.
- The tree search may need only two comparisons, because Frank is a child of the root.
Key Takeaways
- A linear search checks entries one after another from the beginning, so a long plain list of name-number pairs becomes slow and tedious to search.
- A map is a container of pairs of values optimized for lookup, so it suits problems where finding a value by its key is the main task.
- Associative array and dictionary are other names for the same kind of container, depending on the context.
- The standard-library map is implemented as a balanced binary tree, so a lookup follows a short path by choosing the left or right subtree at each node.