ЁЯПл The SchoolтА║ЁЯзо DSAтА║ЁЯЧВя╕П рдзрдбрд╛ 05 тАФ Hash maps рдЖрдгрд┐ sets: рдирд╛рд╡рд╛рдиреБрд╕рд╛рд░ рдХрдкреНрдкреЗ
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЧВя╕П рдзрдбрд╛ 05 тАФ Hash maps рдЖрдгрд┐ sets: рдирд╛рд╡рд╛рдиреБрд╕рд╛рд░ рдХрдкреНрдкреЗ

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 05 ┬╖ рдкреБрдвреЗ: lesson-06-recursion


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ05. dict рдЖрдгрд┐ set рдорд╛рдЧрдЪрд╛ structure, рджрд┐рд╕рдгрд╛рд▒реНрдпрд╛ buckets рд╕рд╣ рдмрдирд╡рд▓реЗрд▓рд╛, рдореНрд╣рдгрдЬреЗ collisions рдЖрдгрд┐ rehashing рдШрдбрддрд╛рдирд╛ рддреБрдореНрд╣рд╛рд▓рд╛ рджрд┐рд╕рддрд╛рдд.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рд▓рд╛ рдПрдХ рдХрдкреНрдкрд╛ рдорд┐рд│рддреЛ, рдЖрдгрд┐ рд╢рд┐рдкрд╛рдпрд╛рдХрдбреЗ рдПрдХ рдирд┐рдпрдо рдЖрд╣реЗ рдЬреЛ рдХреЛрдгрддреНрдпрд╛рд╣реА рдирд╛рд╡рд╛рдЪреЗ box рдХреНрд░рдорд╛рдВрдХрд╛рдд рд░реВрдкрд╛рдВрддрд░ рдХрд░рддреЛ: hash("Dipika") % 8 = 3. рджреАрдкрд┐рдХрд╛рдЪреЗ рдкрддреНрд░ рдареЗрд╡рд╛рдпрд▓рд╛ рдХрд┐рдВрд╡рд╛ рдХрд╛рдврд╛рдпрд▓рд╛ box рдореЛрдЬрд╛, рдЙрдШрдбрд╛ тАФ рдПрдХ step, рд╢рд╛рд│рд╛ рдХрд┐рддреАрд╣реА рдореЛрдареА рдЕрд╕реЛ. рдХрдзреАрдХрдзреА рджреЛрди рдирд╛рд╡реЗ рдПрдХрд╛рдЪ box рдордзреНрдпреЗ рдпреЗрддрд╛рдд (collision): box рдордзреНрдпреЗ рдПрдХ рдЫреЛрдЯреА list рдЕрд╕рддреЗ, рдореНрд╣рдгреВрди рддреБрдореНрд╣реА рдПрдХрд╛рдРрд╡рдЬреА рджреЛрди рдкрддреНрд░реЗ рддрдкрд╛рд╕рддрд╛. boxes рддреАрди рдЪрддреБрд░реНрдерд╛рдВрд╢ рднрд░рд▓реЗ рдХреА рд╢рд┐рдкрд╛рдИ рддреНрдпрд╛рдВрдирд╛ рджреБрдкреНрдкрдЯ рдХрд░рддреЛ рдЖрдгрд┐ рд╕рдЧрд│реЗ рдкреБрдиреНрд╣рд╛ рд▓рд╛рд╡рддреЛ, рдореНрд╣рдгрдЬреЗ boxes рдЫреЛрдЯреЗ рд░рд╛рд╣рддрд╛рдд.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
  K["'Dipika'"] -->|"hash % 8"| B3["box 3: (Dipika, 3A)"]
  Z["'Zoya'"] -->|"hash % 8"| B3
  S["'Katrina'"] -->|"hash % 8"| B6["box 6: (Katrina, 3A)"]

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

"рдЬрд▓рдж рдХрд░рд╛" рдпрд╛рдЪрд╛ рдЕрд░реНрдзрд╛ рднрд╛рдЧ рдореНрд╣рдгрдЬреЗ "рддреЛ рдЖрддрд▓рд╛ loop dict рдиреЗ рдмрджрд▓рд╛". рдирд╛рд╡рд╛рдиреЗ рдЧреЛрд╖реНрдЯреА рд╢реЛрдзрд╛рдпрдЪреНрдпрд╛ рдЕрд╕рддреАрд▓ рддреЗрд╡реНрд╣рд╛ рд╣рд╛рдЪ рдкрд╣рд┐рд▓рд╛ structure рд╣рд╛рддреА рдШреНрдпрд╛рдпрдЪрд╛, рдЖрдгрд┐ рддреНрдпрд╛рдЪреЗ рджреЛрди рдЦрд░реНрдЪ (memory, рдХреНрд░рдо рдирд╛рд╣реА) рдорд╛рд╣реАрдд рдЕрд╕рд▓реЗ рдХреА рддреЛ рдЯрд╛рд│рд╛рдпрдЪрд╛ рдЕрд╢реА рджреБрд░реНрдорд┐рд│ рдкреНрд░рдХрд░рдгреЗ рдХрд│рддрд╛рдд.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

HashMap 25 рдУрд│реАрдВрдЪрд╛ рдЖрд╣реЗ: _slot box рдореЛрдЬрддреЛ, put box рдордзреНрдпреЗ рдЖрдзреАрдЪреА key рдЖрд╣реЗ рдХрд╛ рддреЗ рдкрд╛рд╣рддреЛ, box рд░рд┐рдХрд╛рдорд╛ рдирд╕реЗрд▓ рддрд░ рдПрдХ collision рдореЛрдЬрддреЛ, append рдХрд░рддреЛ, рдЖрдгрд┐ 75% рдУрд▓рд╛рдВрдбрд▓реЗ рдХреА rehash рдХрд░рддреЛ. demo.py hashmap рдЪрд╛рд░ boxes рдиреЗ рд╕реБрд░реВ рд╣реЛрддреЛ рдореНрд╣рдгрдЬреЗ рддреБрдореНрд╣реА рддреЛ рд╡рд╛рдврддрд╛рдирд╛ рдкрд╛рд╣реВ рд╢рдХрддрд╛.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 dsa/demo.py hashmap
python3 - <<'EOF'
import sys; sys.path.insert(0, "dsa"); from structures import HashMap
hm = HashMap(buckets=2)
for i in range(1000): hm.put(f"pupil{i}", i)
print(len(hm), "pupils in", len(hm._b), "boxes; longest box:", max(len(b) for b in hm._b))
# two-sum in one pass with a dict (unsorted input тАФ no two pointers needed):
xs, target, seen = [8, 3, 11, 6, 1], 14, {}
for i, x in enumerate(xs):
    if target - x in seen: print("pair:", seen[target - x], i); break
    seen[x] = i
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

рдЖрда рд╡рд┐рджреНрдпрд╛рд░реНрдереА рд╢реЗрд╡рдЯреА 16 boxes рдордзреНрдпреЗ рдЬрд╛рддрд╛рдд (collision count рдкреНрд░рддреНрдпреЗрдХ run рд▓рд╛ рдмрджрд▓рддреЛ рдХрд╛рд░рдг Python string hashes рдирд╛ salt рд▓рд╛рд╡рддреЛ); рд╢рдмреНрджрд╛рдВрдЪреА рдореЛрдЬрдгреА {'the': 3, тАж}. рддреБрдордЪреЗ рд╣рдЬрд╛рд░ рд╡рд┐рджреНрдпрд╛рд░реНрдереА 2,048 boxes рдордзреНрдпреЗ рдмрд╕рддрд╛рдд рдЖрдгрд┐ рд╕рд░реНрд╡рд╛рдд рд▓рд╛рдВрдм box рдордзреНрдпреЗ рдлрдХреНрдд рдХрд╛рд╣реАрдЪ рдЕрд╕рддрд╛рдд; two-sum pair: 1 2 print рдХрд░рддреЛ (3 + 11).

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

hashing рдореБрд│реЗ lookup O(1) рд╣реЛрддрд╛рдирд╛ рддреБрдореНрд╣реА рдкрд╛рд╣рд┐рд▓реЗ, collisions рд╣рд╛рддрд╛рд│рд▓реЗ рдЬрд╛рддрд╛рдирд╛ рдЖрдгрд┐ boxes рджреБрдкреНрдкрдЯ рд╣реЛрддрд╛рдирд╛ рдкрд╛рд╣рд┐рд▓реЗ, рдЖрдгрд┐ n┬▓ loop рдЪреА рдЬрд╛рдЧрд╛ рдШреЗрдгрд╛рд░рд╛ рдПрдХрд╛ pass рдЪрд╛ dict pattern рд╡рд╛рдкрд░рд▓рд╛.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: caches, sessions, indexes, deduplication, database engine рдордзрд▓реЗ joins, DNS resolvers тАФ hash maps рд╣реЗрдЪ рдХрд╛рдорд╛рдЪреЗ рдШреЛрдбреЗ рдЖрд╣реЗрдд. рд╡рд╛рдИрдЯ hash рдЕрд╕рд▓реЗрд▓рд╛ "O(1)" cache рдореНрд╣рдгрдЬреЗ рдПрдХ incident.

тПня╕П рдкреБрдвреЗ

рдзрдбрд╛ 06 тАФ recursion: рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХ рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХрд╛рдВрдирд╛ рд╡рд┐рдЪрд╛рд░рддрд╛рдд, рдЖрдгрд┐ рдлрд│реНрдпрд╛рд╢рд┐рд╡рд╛рдп fib рдХрд╛ рдлреБрдЯрддреЗ.

ЁЯЧВя╕П Lesson 05 тАФ Hash maps & sets: pigeonholes by name

ЁЯУН You are here: Lesson 05 of 12 ┬╖ Next: lesson-06-recursion


ЁЯУж What's in this branch

Lessons 01тАУ05. The structure behind dict and set, built with visible buckets so you can see collisions and rehashing happen.

ЁЯзТ Explain like I'm 5

Each pupil gets a pigeonhole, and the porter has a rule that turns any name into a box number: hash("Dipika") % 8 = 3. To file or fetch Dipika's letter, compute the box, open it тАФ one step, whatever the school's size. Sometimes two names land in one box (a collision): the box holds a short list, so you check two letters instead of one. When the boxes get three quarters full, the porter doubles them and re-files everything, so boxes stay short.

ЁЯЧ║я╕П Diagram

flowchart LR
  K["'Dipika'"] -->|"hash % 8"| B3["box 3: (Dipika, 3A)"]
  Z["'Zoya'"] -->|"hash % 8"| B3
  S["'Katrina'"] -->|"hash % 8"| B6["box 6: (Katrina, 3A)"]

тЭУ What

ЁЯдФ Why

Half of "make it faster" is "replace that inner loop with a dict". It is the first structure to reach for whenever you look things up by name, and knowing its two costs (memory, no order) tells you the rare cases to avoid it.

ЁЯФз How (in this repo)

HashMap is 25 lines: _slot computes the box, put scans the box for an existing key, counts a collision if the box was non-empty, appends, and rehashes past 75%. demo.py hashmap starts with four boxes so you can watch it grow.

ЁЯзк Try it

python3 dsa/demo.py hashmap
python3 - <<'EOF'
import sys; sys.path.insert(0, "dsa"); from structures import HashMap
hm = HashMap(buckets=2)
for i in range(1000): hm.put(f"pupil{i}", i)
print(len(hm), "pupils in", len(hm._b), "boxes; longest box:", max(len(b) for b in hm._b))
# two-sum in one pass with a dict (unsorted input тАФ no two pointers needed):
xs, target, seen = [8, 3, 11, 6, 1], 14, {}
for i, x in enumerate(xs):
    if target - x in seen: print("pair:", seen[target - x], i); break
    seen[x] = i
EOF

тЬЕ Verify тАФ what you should see

Eight pupils end in 16 boxes (the collision count varies run to run because Python salts string hashes); the word count is {'the': 3, тАж}. Your thousand pupils sit in 2,048 boxes with the longest box holding only a few; two-sum prints pair: 1 2 (3 + 11).

ЁЯПБ What you just proved

You watched hashing turn lookup into O(1), saw collisions handled and boxes doubled, and used the one-pass dict pattern that replaces an n┬▓ loop.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: caches, sessions, indexes, deduplication, joins in a database engine, DNS resolvers тАФ hash maps are the workhorse. A cache that is "O(1)" with a poor hash is an incident.

тПня╕П Next

Lesson 06 тАФ recursion: the head asks the deputy, and why fib without a board explodes.

тЖР Previousstacks queuesNext тЖТrecursion

This page is the lesson's README from the lesson-05-hash-maps branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.