Load Factor ve Hız İlişkisi
Load Factor, hash table'ın ne kadar dolu olduğunu gösteren bir sayıdır.
Az çakışma, hızlı erişim
Çakışmalar artıyor
Çok çakışma (chaining) / Eklenemez (open addressing)
Python dict'in load factor kritik seviyeye gelince (α ≥ 0.67) ne yapar?
→ Tabloyu 2 katına çıkarır ve tüm elemanları yeniden yerleştirir (rehashing)!
Bu sayede performans her zaman O(1) kalır.
Load factor arttıkça arama süresi katlanarak uzuyor!
| Load Factor | Chaining (başarılı arama) |
Chaining (başarısız arama) |
Open Addressing (başarılı arama) |
|---|---|---|---|
| α = 0.5 | 1.25 | 1.5 | 1.5 |
| α = 0.75 | 1.37 | 2.5 | 2.5 |
| α = 0.9 | 1.45 | 5.5 | 5.5 |
Değerler: Ortalama deneme sayısı (probe count)
Load factor kritik seviyeye gelince tablo boyutu artırılır ve tüm elemanlar yeniden yerleştirilir.
⚠️ Maliyetli işlem: O(n) ama nadir olur!
class HashTableWithRehash:
"""Otomatik rehashing yapan hash table"""
def __init__(self, initial_size=4):
self.size = initial_size
self.table = [[] for _ in range(self.size)]
self.count = 0
self.max_load_factor = 0.75 # Kritik seviye
self.rehash_count = 0
def hash_function(self, key):
return key % self.size
def get_load_factor(self):
return self.count / self.size
def rehash(self):
"""Tabloyu büyüt ve yeniden yerleştir"""
self.rehash_count += 1
old_table = self.table
old_size = self.size
# Yeni tablo (2 katı)
self.size = old_size * 2
self.table = [[] for _ in range(self.size)]
self.count = 0
print(f"\n🔄 REHASHING: {old_size} → {self.size}")
print("=" * 40)
# Tüm elemanları yeniden ekle
for bucket in old_table:
for key, value in bucket:
# Yeni hash değeri!
self.insert(key, value, silent=True)
print(f"✅ Rehashing tamamlandı!")
print(f" Yeni load factor: {self.get_load_factor():.2f}")
def insert(self, key, value, silent=False):
"""Eleman ekle (gerekirse rehash yap)"""
# Load factor kontrolü
if self.get_load_factor() >= self.max_load_factor:
if not silent:
print(f"\n⚠️ Load factor kritik: {self.get_load_factor():.2f}")
self.rehash()
index = self.hash_function(key)
# Güncelleme mi?
for i, (k, v) in enumerate(self.table[index]):
if k == key:
self.table[index][i] = (key, value)
if not silent:
print(f"Güncellendi: {key} → indeks {index}")
return
# Yeni ekleme
self.table[index].append((key, value))
self.count += 1
if not silent:
print(f"Eklendi: {key} → indeks {index} (LF: {self.get_load_factor():.2f})")
def display_stats(self):
print(f"\n📊 İstatistikler:")
print(f" Tablo boyutu: {self.size}")
print(f" Eleman sayısı: {self.count}")
print(f" Load factor: {self.get_load_factor():.2f}")
print(f" Rehash sayısı: {self.rehash_count}")
print(f" En uzun zincir: {max(len(b) for b in self.table)}")
# Test
ht = HashTableWithRehash(initial_size=4)
print("=== Hash Table ile Ekleme (Rehashing İzle) ===")
print(f"Başlangıç boyutu: 4, Max load factor: 0.75")
print()
# 10 eleman ekle - rehashing'leri gözlemle
for i in range(1, 11):
print(f"\n--- {i}. eleman ekleniyor ---")
ht.insert(i * 3, f"değer_{i}")
ht.display_stats()
# Son durum
print("\n=== Son Tablo Durumu ===")
for i in range(min(ht.size, 16)): # İlk 16 indeks
if ht.table[i]:
keys = [k for k, v in ht.table[i]]
print(f"[{i:2d}]: {keys}")
else:
print(f"[{i:2d}]: boş")
Rehashing O(n) zaman alıyor. Peki hash table insert işlemi O(1) mi, O(n) mi?
Çoğu insert O(1), sadece seyrek olarak rehashing oluyor:
Python'da hash table nasıl kullanılır? dict'in sırlarını keşfedeceğiz!