3
$\begingroup$

I'm looking for an data structure that supports efficient random prefix matching queries (pattern) over a previously known set of words (dictionary). The dictionary is expected to contain about 10,000 words of varying length (I haven't calculated average word length, but I don't expect any word to be more than 80 characters long). Prefix matching in this case would be equivalent to words[i].toLowerCase().startsWith(pattern.toLowerCase()).

A Trie is an obvious choice, and provides linear time search corresponding to the length of the pattern. However, I'm confused whether a Suffix Tree, or a Suffix Array, might provide any improvements over a Trie. It seems a Suffix whatever is commonly used for one text, not multiple. I also have no requirement for supporting the various cool use cases (longest common prefix, or number of times a prefix occurs etc) that Suffix whatever can efficiently support.

I'm looking for a recommendation on which data structure to use, and why. Tries use a lot of space, and if I end up using one, I'd consider compress the branches with nodes with outdegree 1.

For the duplicate button happy readers, I've read this and this question, none seemed directly relevant.

Example:

Dictionary: [banana, apple, banter, orange]

Pattern: ban
Return: banana (any match)

Pattern: grapes
Return: null
$\endgroup$
3
  • 2
    $\begingroup$ What does "prefix matching queries (pattern)" mean? Can you specify the operation that you want to perform on the data structure more carefully? $\endgroup$
    – D.W.
    Commented Feb 24, 2019 at 1:27
  • 1
    $\begingroup$ @Evil It's specified already in my example, any match, assuming "banana" is the path the code chose. "banter" would be a perfectly acceptable answer too. $\endgroup$ Commented Feb 24, 2019 at 2:02
  • $\begingroup$ @D.W. I thought it was plenty obvious what prefix match means, but I've updated my question with a code snippet to demonstrate it explicitly. $\endgroup$ Commented Feb 24, 2019 at 2:04

2 Answers 2

6
$\begingroup$

A trie is asymptotically optimal for this. No data structure can achieve better asymptotic running time.

If you care about constant factors, the only way to know what will be optimal is to try multiple approaches and benchmark them. Standard theoretical running time analysis is not reliable at predicting constant factors.

Another data structure to consider is to store every prefix of each word in a hashtable. This will increase the space usage by about 10x (if the average word length is 10) but might speed up lookups in practice. The asymptotic running time will remain the same. You'll have to decide whether you're willing to trade off space for time.

Suffix trees and suffix arrays don't seem relevant. You're asking about prefix matching, not suffix matching or matching in the middle of the string.

$\endgroup$
2
  • $\begingroup$ While I agree with you regarding using Trie, I don't think the claim "Suffix trees and suffix arrays don't seem relevant. You're asking about prefix matching, not suffix matching" holds. One of the most common uses of a suffix tree/array is pattern matching or substring search. See this or this paper. $\endgroup$ Commented Feb 24, 2019 at 2:15
  • $\begingroup$ @AbhijitSarkar, yes, I know how they are used for that; that's for finding an instance of the pattern in the middle of the string. Here you want to anchor the pattern so it is only allowed to occur at the beginning of the string. Suffix trees/arrays don't seem relevant for the latter. (If you think they're useful for that, I suggest trying to work out a specific algorithm for how you would use a suffix tree to help you answer that query, and then maybe you'll see what I mean; or else you'll have some more details you can add to your question to highlight whatever I've overlooked...) $\endgroup$
    – D.W.
    Commented Feb 24, 2019 at 3:36
1
$\begingroup$

Another possibility would be to store all the words in an array, sort it, and then do lookups on it using binary-search.

Disadvantages compared to a Trie:

  • Worse asymptotic time complexity for lookups ($O(\mathrm{log}\ n)$ average where n is the number of entries).
  • Probably less efficient to insert additional entries, as the array will need to be resized.

Advantages compared to a Trie:

  • Probably more efficient to build if all entries are added in one go with no further modification.
  • Uses less memory.
  • Lookups are probably more CPU-cache friendly if the array isn't too large, due to the entries being consecutive in memory (see locality).
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.