3.3.7 · Coding › Hashing
Ek akela operation kabhi kabhi expensive ho sakta hai (jaise poora array resize karna), lekin agar woh expensive step itni kam baar hota hai , toh har operation ki average cost ek lambi run mein phir bhi constant rehti hai. Usi average ko hum amortized O(1) kehte hain.
Ise phone bill ki tarah socho: ek mahine mein ₹2000 setup fee dete ho, lekin 24 mahino mein spread karo toh sirf ₹83/mahina extra hai. Badi cost kaafi saare saste mahino mein amortized ho jaati hai.
Definition Amortized cost
Kisi operation ki amortized cost n operations ki sequence ki total cost ko n se divide karne par milti hai, jo ek upper bound guarantee karta hai — chahe individual operations vary karein.
Amortized cost = n Total cost of n operations
Yeh average-case se BILKUL alag hai (jo probability use karta hai). Amortized analysis ek sequence pe worst-case guarantee hai — koi randomness nahi.
Teen standard methods:
Aggregate method — total cost / n.
Accounting method — har saste op ko thoda extra charge karo ("credit") taaki future ke expensive ops pre-pay ho sakein.
Potential method — ek potential function Φ define karo jo "bacha hua" kaam store kare.
Ek dynamic array (Python list, C++ vector, Java ArrayList) ya open-addressing hash table ki fixed capacity hoti hai. Jab yeh bhar jaata hai, tumhe:
Ek bada block allocate karna padta hai.
Har existing element ko copy karna padta hai — ek O ( n ) step.
Agar array ko har baar +1 badhao, toh har insert ek copy trigger karega → total cost O ( n 2 ) . Trick yeh hai ki capacity double karo taaki copies rarely hon.
Maan lo hum empty se shuru karte hain aur n items push karte hain. Jab bhi array full ho, hum capacity double karte hain. Capacities jo milti hain: 1 , 2 , 4 , 8 , …
Step 1 — saste inserts. n mein se har ek push element likhne ke liye 1 cost karta hai.
cheap cost = n
Yeh step kyun? Har element exactly ek baar apni slot mein likha jaata hai.
Step 2 — resizes par copy costs. Capacity 2 k par resize 2 k purane elements copy karta hai. Resizes sizes 1 , 2 , 4 , … , 2 m par hote hain jahan 2 m ≤ n .
copy cost = 1 + 2 + 4 + ⋯ + 2 m = ∑ i = 0 m 2 i = 2 m + 1 − 1
Yeh step kyun? Geometric series — har doubling current poore array ko ek baar copy karta hai.
Step 3 — sum ko bound karo. Kyunki 2 m ≤ n hai, hame 2 m + 1 − 1 < 2 n milta hai.
copy cost < 2 n
Step 4 — total aur divide.
Total = n + 2 n = 3 n = O ( n )
Amortized cost per push = n 3 n = 3 = O ( 1 )
Yeh kyun kaam karta hai: copies ek geometric series banate hain jo n ke constant multiple mein sum hoti hai , n 2 mein nahi. Rare doublings "pay" hoti hain unse pehle ke kaafi saare saste inserts se.
Intuition Aage ke liye pay karo
Har push ko ₹3 (3 units of credit) charge karo chahe likhne mein sirf ₹1 lagta ho.
₹1 actual write ke liye pay karta hai.
₹2 element par credit ke roop mein save ho jaate hain.
Jab doubling hoti hai, copy hone wala har element apna saved credit ka ₹1 use karta hai, aur yeh kaafi hota hai kyunki do resizes ke beech array roughly double hua hoga — har purane element ne ek naaye element ke paas credit accumulate kar liya hai. Toh bank kabhi negative nahi jaata → amortized cost ≤ 3 = O ( 1 ) .
Worked example Example 1 — n = 5 ke liye copies count karna
Array mein pushes, cap 1 se doubling: capacities used 1,2,4,8.
Push 1: full(cap1)→no resize , write. cost 1
Push 2: full(cap1)→resize→cap2, copy 1, write. cost 2
Push 3: full(cap2)→resize→cap4, copy 2, write. cost 3
Push 4: write (cap4 mein jagah hai). cost 1
Push 5: full(cap4)→resize→cap8, copy 4, write. cost 5
Total = 1+2+3+1+5 = 12. Amortized = 12/5 = 2.4 ≤ 3 . ✅
Yeh step kyun? Copies (1+2+4=7) plus writes (5) = 12 — hamare n + ( 2 n − 1 ) bound se match karta hai.
Worked example Example 2 — Hash table insert
Ek open-addressing hash table load factor α = size / capacity ≤ 0.5 maintain karta hai. Jab α threshold se zyada ho, rehash karo — saare elements ko doubled table mein le jao (O ( n ) ). Usi geometric-series argument se , n inserts par total rehash work < 2 n hoti hai, toh insert amortized O(1) hai (ek accha hash assume karo → O(1) per probe).
Yeh step kyun? Rehashing = resizing + re-placing; cost structure dynamic array jaisii hi hai.
Worked example Example 3 — Growth factor kyun matter karta hai
Agar hum har baar +1 badhate: copy cost = 1 + 2 + ⋯ + ( n − 1 ) = 2 n ( n − 1 ) = O ( n 2 ) . Amortized = O ( n ) — constant nahi! Doubling (factor 2, ya koi bhi factor > 1 ) zaroori hai.
Yeh step kyun? Arithmetic series quadratically badhti hai; geometric series linear rehti hai.
Common mistake "Amortized O(1) matlab har operation O(1) hai."
Kyun sahi lagta hai: "O(1)" fast suggest karta hai, har baar.
Fix: Ek resize genuinely O ( n ) hai — ek worst-case latency spike. Amortized sirf ek sequence ke total ko bound karta hai. Real-time systems mein jahan ek slow op bhi acceptable nahi, amortized guarantees kaafi nahi ho sakti.
Common mistake "Amortized = average-case."
Kyun sahi lagta hai: dono ek "average per op" dete hain.
Fix: Average-case random inputs par probability use karta hai. Amortized operations ki sequence par deterministic worst-case hai — bilkul bhi probability nahi. Doubling ≤ 3 guarantee karta hai chahe input order kuch bhi ho.
Common mistake "Fixed +10 chunk se grow karna theek hai kyunki yeh bada hai."
Kyun sahi lagta hai: bade jumps mein kam resizes lagte hain.
Fix: Koi bhi constant additive growth O ( n ) resizes deti hai, har ek O ( n ) copy karta hai → O ( n 2 ) total → O ( n ) amortized. O(1) ke liye multiplicative (geometric) growth chahiye.
"Amortized O(1)" ka precise matlab kya hai? n operations ki total cost O(n) hai, toh sequence mein average cost per operation O(1) hai — yeh sequence par worst-case guarantee hai, single op per nahi.
Array capacity doubling amortized O(1) per insert kyun hai? Copy costs geometric series 1+2+4+…+2^m < 2n banate hain, plus n writes → total 3n = O(n), toh 3 per op.
Har baar +1 se grow karne par total copy cost aur amortized cost kya hai? Copy cost = n(n-1)/2 = O(n²); amortized = O(n), constant nahi.
Amortized aur average-case complexity mein kya fark hai? Amortized = sequence par deterministic worst-case; average-case = inputs ki probability distribution par expectation.
Dynamic array doubling ke liye use ki gayi potential function batao. Φ = 2·size − capacity (≥0 jab ≥ aadha bhar ho).
Accounting method mein har push ko kitna charge hota hai aur kyun? 3 units: 1 write ke liye, 2 credit ke roop mein save hote hain future mein apni aur ek neighbour ki copies pay karne ke liye.
Real-time systems mein amortized O(1) acceptable kyun nahi ho sakta? Ek single resize O(n) hai — ek latency spike — chahe average constant ho.
Amortized O(1) inserts guarantee karne ke liye growth factor ki kya requirement hai? Multiplicative (geometric) growth kisi bhi factor > 1 se; additive growth fail ho jaati hai.
Recall Feynman: ek 12-saal ke bacche ko samjhao
Socho tum ek chote se box mein khilone bhar rahe ho. Jab woh bhar jaata hai, tum ek box do guna bada khareed te ho aur saare khilone us mein move karte ho — yeh move slow hota hai. Lekin kyunki har naya box pichle se double hota hai, saikdon khilone ke baad bhi tum khilone sirf kuch hi baar move karte ho. Toh zyaadatar time khilona add karna bahut fast hai, aur rare slow moves spread out karne par chhoti lagte hain. Average mein, ek khilona add karna fast hai — yahi "amortized O(1)" hai.
"Double karo, add mat karo — rare cost spread ho jaati hai."
Geometric linear rehti hai; arithmetic square ho jaati hai.
1 + 2 + 4 + ⋯ < 2 n (sasta) vs 1 + 2 + 3 + ⋯ = n 2 /2 (expensive).
Dynamic Arrays — geometric resizing ka primary use case.
Hash Tables — load-factor threshold par rehashing yahi argument use karta hai.
Load Factor — open addressing mein resize trigger karta hai.
Geometric Series — yeh math hai jo doubling ko linear rakhti hai.
Big-O Notation — amortized asymptotic analysis ka ek flavor hai.
Potential Method — yahan use ki gayi formal accounting technique.
Stack with Multipop — amortized analysis ka ek aur classic example.
Worst-case guarantee over sequence
Average-case with probability
Dynamic array / hash table