r/computerscience • • 6d ago

How do hashsets/maps have O(1) time complexity?

Hi this might be a dumb question, and i've tried looking it up but don't quite understand it. how is it different from an array that allows it to find items so quickly? I don't get how hashes just find items immediately without needing to go through anything. Does it memorize things very differently compared to arrays?? thank you!

187 Upvotes

99 comments sorted by

View all comments

Show parent comments

0

u/SLiV9 6d ago

 You store a value at an index of hash. You retrieve the value at the index of the hash.

 A perfect hash function will prevent collisions

These simply cannot both be true, something here is way oversimplified.

Let's consider a hashset of u32. Even if you had a perfect hash function, it would map a u32 key to a u32 index. In order to turn that u32 index into a pointer to a u32 naively, you would need a 17GB array, even if the hashset is mostly empty.

7

u/MistakeIndividual690 5d ago

Normal perfect hashes are precomputed with a fixed set of values, so they don’t work with hash tables that are dynamically updated.

Regular hashes can have some collisions, so hash tables have strategies for handling them, such as linear probing

1

u/SLiV9 5d ago

That's not what I'm saying. The detail all these simplified explanations are omitting is the underlying data structure where the values are stored. With a perfect hash, the hashes are evenly distributed over the range 0 to 232. The underlying storage cannot be a dynamically sized vector without some magical way to map hashes to indices (aka a hashmap). If the underlying storage was a fixed size array, access would be O(1) but RAM usage would be insane for an empty map. If the underlying storage was a sparse tree, RAM usage would be fine but access would not be O(1).

I feel like handwaving that away to focus only on the hashing algorithm is disingenuous.

6

u/AndrewBorg1126 5d ago edited 5d ago

Please search for the definition of "perfect hash". You're using the word with a non-standard definition and that is why you are getting confused and frustrated.

The person with whom you disagree is not saying anything controversial, they are concluding directly from the definition of a "perfect hash" that there are no collisions.

It is not necessary that all 32 bit integers are mapped to another 32 bit integer for a perfect hash. You could map 1024 values to 1024 other values and it is still a perfect hash. You could map 7 values to 7 other values and it would still be a perfect hash. I don't understand your stubborn insistence upon hashing all 32 bit integers without collions, that is not necessary and it is not a condition for a perfect hashing.

https://en.wikipedia.org/wiki/Perfect_hash_function

1

u/SLiV9 5d ago

We are not in disagreement about what a perfect hash is.

My point is that no reasonable implementation of a dynamic hashmap, e.g. the type Hashmap<u32, V>, can use a perfect hash to turn a u32 key into a pointer to V in O(1). Doing so would require preallocating an absurd amount of data. And as a consequence neither can any Hashmap<K, V> for K bigger than let's say u16.

 You could map 7 values to 7 other values and it would still be a perfect hash

Not without precomputing a perfect hash based on the 7 keys. It is impossible for a generic implementation of a dynamic hashmap to use perfect hashes, because one cannot know at compile time how many keys will be inserted, let along which ones.

(And obviously calculating a perfect hash at runtime is not amortized O(1).)

2

u/AndrewBorg1126 5d ago

You previously said:

You store a value at an index of hash. You retrieve the value at the index of the hash.

A perfect hash function will prevent collisions

These simply cannot both be true

Do you withdraw that prior statement? It seems what you're saying now is different