views:

165

answers:

3

I'm trying to figure out what data structure to quickly support the following operations:

  • Add a string (if it's not there, add it, if it is there, increment a counter for the word)
  • Count a given string (look up by string and then read the counter)

I'm debating between a hash table or a trie. From my understanding a hash table is fast to look up and add as long as you avoid collisions. If I don't know my inputs ahead of time would a trie be a better way to go?

A: 

Either one is reasonably fast.

It isn't necessary to completely avoid collisions.

Looking at performance a little more closely, usually, hash tables are faster than trees, but I doubt if a real life program ever ran too slow simply because it used a tree instead of a HT, and some trees are faster than some hash tables.

What else can we say, well, hash tables are more common than trees.

One advantage of the complex trees is that they have predictable access times. With hash tables and simple binary trees, the performance you see depends on the data and with an HT performance depends strongly on the quality of the implementation and its configuration with respect to the data set size.

DigitalRoss
+2  A: 

It really depends on the types of strings you're going to be using as "keys". If you're using highly variable strings, plus you do not have a good hash algorithm for your strings, then a trie can outperform a hash.

However, given a good hash, the lookup will be faster than in a trie. (Given a very bad hash, the opposite is true, though.) If you don't know your inputs, but do have a decent hashing algorithm, I personally prefer using a hash.

Also, most modern languages/frameworks have very good hashing algorithms, so chances are, you'll be able to implement a good lookup using a hash with very little work, that will perform quite well.

Reed Copsey
What would suggest though if I'm designing this data structure from scratch. It's for a project where we can base it off any data structure, but we have to design everything using C++. The project is graded based on the speed of the add/search methods. There's probably going to be an input of hundreds of thousands of random strings. I don't have any experience implementing hash tables or tries, so I'm wondering which would be a better bet.
Carol
Trie is easier to implement. Hash table is probably easier to get "right", especially since there are lots of samples out there. Chances are, you'll do better with a hash table in terms of grades - just make sure to try to get a good string hashing algorithm (since that makes adds/removes very fast).
Reed Copsey
I just thought of something else - if you don't have control over WHAT strings are going to be added or removed, use a hash. Trie can degrade very badly if you're feeding it "bad" strings... so the insert/removal speed can be very poor with bad strings. Hash will only degrade if you have hash collisions, which won't happen (much) with a good hashing algorithm.
Reed Copsey
What's an example of a bad string? Also, do you think there's any disadvantage of having to grow the hash table if there starts to be too many inputs?
Carol
Well, it depends on your implementation. Trie, for example, with most implementations, do very poorly if the beginning of the string is the same, and only the "end" portion is different. Shared "prefix" values in a trie basically make it move towards O(n) for lookup, with "n" being the length of the string. Long strings that start with similar values will perform very poorly. Hashes, on the other hand, don't care - changing any value adjusts the hash, so a good hashing algorithm prevents those types of degredation issues.
Reed Copsey
+1  A: 

A trie won't buy you much; they're only interesting when prefixes are important. Hash tables are simpler, and usually part of your language's standard library, if not directly part of the language itself (Ruby, Python, etc). Here's a dead-simple way to do this in Ruby:

strings = %w(some words that may be repeated repeated)
counts = Hash.new(0)
strings.each { |s| counts[s] += 1 }
#counts => {"words"=>1, "be"=>1, "repeated"=>2, "may"=>1, "that"=>1, "some"=>1}

Addenda: For C++, you can probably use Boost's hash implementation.

Bob Aman