Probably a data structure consisting of a pair of tries might work well. One trie would give you a phone numbers given a name, and the other would give you names given a phone number.
The nodes of the tree which gives you phone numbers for a name would have edges labeled with symbols making up the name. The value associated with each vertex would be pointer to a node in the other trie (the one that gives you names for phone numbers) corresponding to the phone number of the person whose name leads from the root to the vertex. Given a name, you can thus return the corresponding phone number of the person with that name (by traversing from the linked node to the root). In fact, you could use this to find all people whose names begin with a certain prefix and their corresponding phone numbers.
Here's an example of the name-to-phone number trie:
J A C K
1--->2--->3--->4--->5
| |
I | S V
| 9--->10--->11
V O N
6--->7--->8
L L
Suppose the people represented are Jack, Jill, Jason and Jaso (a foreign exchange student). The other trie might look like this:
1 2 3
A--->B--->C--->D
| |
3 | V 2
| E
V 3
F--->G
|
2 |
V
H
The phone numbers are 123, 122, 133 and 132.
Now, the references will look like this:
Name Trie Number Trie
--------- -----------
1->null A->null
2->null B->null
3->null C->null
4->null D->10
5->E E->5
6->null F->null
7->null G->8
8->G H->11
9->null
10->D
11->H
Upon input JAS
to the name trie, we can determine easily that there are no numbers for this name since node 9
has no corresponding number. Suppose we want to list all numbers for people whose name starts thusly. We can traverse the tree using whatever method you like (an inorder traversal based on alphabetical order would seem sane) gives JASO (10)
and JASON (11)
which we see do have corresponding nodes in the phone number trie.
For each of these nodes, we can jump to the phone numbers trie and work our way back up to the parent (assuming we saved the parent reference in each node, which is doable). Along the way, we can keep track of the edge labels to derive the number corresponding to our node. Since 10->D
, we find C
, B
and A
on the way back to the root A
and the digits along the way were 3
, 2
and 1
. By concatenating them in the order seen during backtracking, and subsequently reversing that concatenation, we obtain the string that leads from A
to D
, thus the one corresponding to JASO
: 123
. Similarly for JASON
.
Adding a new entry means simultaneously adding an entry to both tries, and then linking them. If duplicate names or numbers are allowed, then instead of pointing to one node in the other trie, a collection of nodes could be referenced. Removing an entry means simply removing the corresponding node from each tree. Valid names are ones with phone numbers referenced. Valid phone numbers are ones with names referenced.