Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Python dict stores key, value when collision occurs? [duplicate]

How Python stores the dict key, values when collision occurs in hash table? Whats the hash algorithm used to get the hash value here?

like image 242
ShanmugavelSubramani Avatar asked Feb 06 '14 05:02

ShanmugavelSubramani


People also ask

How does Python dictionary deal with collisions?

Python uses a method called Open Addressing for handling collisions. It also resizes the hash tables when it reaches a certain size, but we won't discuss that aspect. Open Addressing definition from Wikipedia: In another strategy, called open addressing, all entry records are stored in the bucket array itself.

What will happen if a dictionary has duplicate keys Python?

Dictionary literals are constructed in the order given in the source. This means that if a key is duplicated the second key-value pair will overwrite the first as a dictionary can only have one value per key.

Do Python dictionary allow duplicate keys?

Dictionaries in Python First, a given key can appear in a dictionary only once. Duplicate keys are not allowed.

What happens when duplicate keys encountered during assignment in dictionary?

Properties of Dictionary Keys When duplicate keys are encountered during the assignment, the value will be the last assigned one. Keys must be immutable. This means you can use strings, numbers, or tuples as dictionary keys, but something like ['key'] is not allowed.


2 Answers

For the "normal" Python, this great writeup by Praveen Gollakota explains it very well, here are the important bits:

  • Python dictionaries are implemented as hash tables. Hash tables consist of slots, and keys are mapped to the slots via a hashing function.
  • Hash table implementations must allow for hash collisions i.e. even if two keys have same hash value, the implementation of the table must have a strategy to insert and retrieve the key and value pairs unambiguously.
  • Python dict uses open addressing to resolve hash collisions (see dictobject.c:296-297).
  • In open addressing, hash collisions are resolved by probing (explained below) .
  • The hash table is just a contiguous block of memory (like an array, so you can do O(1) lookup by index).
  • Each slot in the hash table can store one and only one entry. This is important.
  • Each entry in the table actually a combination of the three items - <hash, key, value>. This is implemented as a C struct (see dictobject.h:51-56).
  • When a new dict is initialized, it starts with 8 slots. (see dictobject.h:49)
  • When adding entries to the table, we start with some slot, i that is based on the hash of the key. CPython uses initial i = hash(key) & mask, where mask = PyDictMINSIZE - 1, but that's not really important. Just note that the initial slot, i, that is checked depends on the hash of the key.
  • If that slot is empty, the entry is added to the slot (by entry, I mean, <hash|key|value>). But what if that slot is occupied!? Most likely because another entry has the same hash (hash collision!)
  • If the slot is occupied, CPython (and even PyPy) compares the hash and the key (by compare I mean == comparison not the is comparison) of the entry in the slot against the key of the current entry to be inserted (dictobject.c337,344-345). If both match, then it thinks the entry already exists, gives up and moves on to the next entry to be inserted. If either hash or the key don't match, it starts probing.
  • Probing just means it searches the slots by slot to find an empty slot. Technically we could just go one by one, i+1, i+2, ... and use the first available one (that's linear probing). But for reasons explained beautifully in the comments (see dictobject.c:33-126), CPython uses random probing. In random probing, the next slot is picked in a pseudo random order. The entry is added to the first empty slot. For this discussion, the actual algorithm used to pick the next slot is not really important (see dictobject.c:33-126 for the algorithm for probing). What is important is that the slots are probed until first empty slot is found.
  • The same thing happens for lookups, just starts with the initial slot i (where i depends on the hash of the key). If the hash and the key both don't match the entry in the slot, it starts probing, until it finds a slot with a match. If all slots are exhausted, it reports a fail.
  • To avoid slowing down lookups, the dict will be resized when it is two-thirds full (see dictobject.h:64-65).
like image 193
Burhan Khalid Avatar answered Sep 22 '22 03:09

Burhan Khalid


The short version: The Python spec doesn't specify a dictionary implementation, but CPython uses a hash map and handles collisions with open addressing.

See this answer to a similar question and also the Wikipedia page on hash tables.

like image 20
Andrew Gorcester Avatar answered Sep 19 '22 03:09

Andrew Gorcester