Step 1 — Map a hash to a starting slot.
The table has m slots, and in CPython m is always a power of two. To turn a possibly-huge
hash into a valid index we take the low bits:
i0=h&(m−1)Why this step? When m=2k, h & (m-1) keeps the lowest k bits, which equals h % m but is
faster — and it gives a value in [0,m−1], a legal index.
Step 2 — Probe if the slot is occupied by a different key.
A naive probe is linear probingin+1=(in+1)modm. Problem: it makes long runs
(clustering). CPython uses a perturbed probe that mixes in the high bits of the hash so
different keys with the same low bits diverge quickly:
in+1=(5in+1+perturb)&(m−1),perturb≫=5Why this step? The high bits of h (carried in perturb) only enter i_0 through the & (m-1)
mask, so they are ignored at first. Feeding them in over successive probes guarantees the
sequence eventually visits every slot, so an item is never lost.
Step 3 — Stop conditions.
At each probed slot:
EMPTY → key is not present (stop). For insert, place it here.
Imagine a wall of numbered lockers. To store your bag you don't pick a locker randomly — you run
your name through a little machine that spits out a locker number. Next time you want your bag,
you run your name through the same machine, get the same number, and go straight to that
locker. Fast! Sometimes two people get the same number (a "clash"); then there's a fixed rule
("try the next one this special way") so everyone still finds their stuff. When the lockers get
too crowded, we move everyone to a bigger wall so searching stays quick.
What collision strategy does CPython dict/set use?
Open addressing (probing inside one array), not separate chaining.
First slot index for hash h, table size m (power of two)?
i0 = h & (m - 1), equivalent to h % m but faster.
CPython's perturbed probe recurrence?
i = (5*i + 1 + perturb) & (m-1); perturb >>= 5 each step, mixing in high bits.
Why feed high bits of the hash into the probe sequence?
The initial index only uses low bits; high bits ensure keys with equal low bits diverge and every slot is eventually visited.
What count and threshold trigger a CPython resize?
When fill > (2/3)*m, where fill = active entries PLUS DUMMY (deleted) slots.
Is α = 5/8 enough to trigger resize at m=8?
No — 5/8 = 0.625 < 2/3 ≈ 0.667; resize needs fill ≥ 6 (since (2/3)*8 = 5.33).
Expected probes for unsuccessful open-addressing search?
1/(1-α); at α=2/3 that's ~3 probes.
Why is deletion marked DUMMY not EMPTY?
EMPTY would prematurely terminate probe chains, hiding keys stored further along; DUMMY keeps chains intact, is reusable on insert, and is counted in fill.
Why are dummies counted in fill?
They lengthen probe chains without being live keys, so counting them forces a cleansing resize before lookups degrade.
Why can't a list be a dict key?
Lists are mutable → unhashable; a changing hash would make the key unfindable.
Why do d[1], d[1.0], d[True] collapse to one entry?
1 1.0 True and their hashes are all 1, so the table treats them as the same key.
Is dict's insertion order stored in the hash slots?
No — order is kept in a separate compact entry/index array; sets don't preserve order at all.
Amortized cost of n inserts despite O(n) resize?
O(1) amortized; a resize occurs only after ~m inserts, spreading its O(n) cost.
Socho ek dict ek lockers ki line hai — ek array jisme fixed number of "slots" hain. Jab tum
d[key] = value karte ho, Python pehle hash(key) nikalta hai (ek bada integer), phir
h & (m-1) se ek slot index banata hai jahan se start karna hai. Yahi trick lookup ko O(1) banati
hai: agle baar same key ka same hash, same index, seedha pohonch gaye. List me x in lst poora
scan karta hai (O(n)), dict me nahi.
Problem tab aati hai jab do keys ka same starting slot ban jaye — isko collision bolte hain.
CPython ka solution open addressing hai: agle slots ko ek special perturbed formula
(5*i + 1 + perturb) & (m-1) se try karta hai, aur perturb me hash ke high bits daal ke keys ko
scatter karta hai taaki clustering na ho aur har key milti rahe.
Resize ka rule dhyaan se: jab fill > (2/3)*m ho tab table bada hota hai. Important — fill sirf
active keys nahi, active entries + DUMMY (deleted) slots dono count karta hai. Isliye agar bahut
delete karoge to dummies bhi fill badha denge aur resize trigger ho jayega (jo dummies clean kar
deta hai). Ek galti se bacho: 5/8=0.625 jo 2/3≈0.667 se chhota hai, to m=8,n=5 par resize nahi hota; threshold (2/3)⋅8=5.33 hai, yaani fill 6 pe trigger. Resize ke
time har key rehash hoti hai kyunki index m par depend karta hai — yeh kabhi-kabhi O(n) kaam
hai, isliye average O(1) amortized rehta hai.
Exam/interview ka 80/20: keys immutable/hashable honi chahiye (list key nahi ban sakti),
1 == 1.0 == True same key bante hain, average O(1) but worst case O(n), aur set order guarantee
nahi karta jabki dict insertion order rakhta hai (par alag order-array me, hash slots me nahi).
Bas itna solid ho gaya to topic clear.