🔢 8.2: Hash Fonksiyonları

Anahtarı İndekse Dönüştürmek - Basit ve Anlaşılır

🎯 Hash Fonksiyonu Nedir?

Hash fonksiyonu, herhangi bir veriyi (anahtar) alıp, onu bir sayıya (indeks) dönüştüren matematiksel bir fonksiyondur.

🌍 Günlük Hayattan Örnek

Kütüphanede kitaplar konularına göre raflara yerleştirilir:

  • "Matematik" → Raf 3
  • "Tarih" → Raf 7
  • "Edebiyat" → Raf 2

Hash fonksiyonu, kitap konusunu (anahtar) alıp raf numarasını (indeks) veriyor!

🧪 İnteraktif Hash Fonksiyonu Deneyi

Bir kelime girin ve farklı hash fonksiyonlarının nasıl çalıştığını görün

📚 Hash Fonksiyonu Özellikleri

İyi bir hash fonksiyonu şu özelliklere sahip olmalıdır:

⚡ Hızlı

Hash hesaplama çok hızlı olmalı (O(1) zaman)

📊 Düzgün Dağılım

Anahtarları tabloya eşit şekilde dağıtmalı

🎯 Deterministik

Aynı anahtar her zaman aynı indeksi vermeli

🔢 1. Division Method (Bölme Yöntemi)

En basit ve en yaygın kullanılan yöntem!

Formül

hash(key) = key % table_size

(key'i table_size'a böl, kalanı al)

💡 Örnek

Tablo boyutu: 10

  • hash(25) = 25 % 10 = 5
  • hash(38) = 38 % 10 = 8
  • hash(123) = 123 % 10 = 3
📝 Ne Zaman Kullanılır?

✅ Sayısal anahtarlar için (ID, telefon numarası, etc.)

✅ Basit ve hızlı

✅ Anlaşılması kolay

✅ Artıları

  • Çok basit ve hızlı
  • Hesaplaması kolay
  • Bellek tasarrufu

❌ Eksileri

  • Tablo boyutu önemli
  • Ardışık sayılar sorun çıkarabilir
  • Kötü boyut seçimi → çakışma
⚠️ Önemli İpucu:

Tablo boyutunu asal sayı seçin! (7, 11, 13, 17, 19...)
Bu, daha iyi dağılım sağlar ve çakışmaları azaltır.

Division Method - Python
def hash_division(key, table_size):
    """Bölme yöntemi ile hash hesapla"""
    return key % table_size

# Örnek kullanım
table_size = 11  # Asal sayı - önemli!

# Farklı anahtarlar için hash değerleri
keys = [25, 38, 123, 456, 789]

print(f"Tablo boyutu: {table_size}")
print(f"{'Anahtar':<10} {'Hash Değeri':<15}")
print("-" * 25)

for key in keys:
    hash_value = hash_division(key, table_size)
    print(f"{key:<10} {hash_value:<15}")

# String anahtarlar için
def hash_string_division(text, table_size):
    """String'i önce sayıya çevir, sonra hash hesapla"""
    # Karakterlerin ASCII değerlerini topla
    total = sum(ord(char) for char in text)
    return total % table_size

print("\n=== String Anahtarlar ===")
words = ["elma", "armut", "muz", "çilek"]
print(f"{'Kelime':<10} {'ASCII Toplamı':<15} {'Hash':<10}")
print("-" * 35)

for word in words:
    ascii_sum = sum(ord(c) for c in word)
    hash_val = hash_string_division(word, table_size)
    print(f"{word:<10} {ascii_sum:<15} {hash_val:<10}")
Çıktı bekleniyor...

✨ 2. Multiplication Method (Çarpma Yöntemi)

Daha gelişmiş bir yöntem - tablo boyutundan bağımsız çalışır!

Formül

hash(key) = ⌊ m × (key × A mod 1) ⌋

A: 0 ile 1 arasında bir sabit (genelde: 0.6180339887... - altın oran)
m: Tablo boyutu
mod 1: Sadece ondalık kısmı al

💡 Adım Adım Örnek

key = 123, A = 0.618, m = 10

  1. 123 × 0.618 = 76.014
  2. 76.014 mod 1 = 0.014 (sadece ondalık kısım)
  3. 10 × 0.014 = 0.14
  4. ⌊0.14⌋ = 0 (tam kısım)

✅ Artıları

  • Tablo boyutu asal olmak zorunda değil
  • Genelde 2'nin kuvveti kullanılır (8, 16, 32...)
  • Daha iyi dağılım

❌ Eksileri

  • Biraz daha yavaş
  • Çarpma işlemi gerekir
  • A sabiti önemli
Multiplication Method - Python
import math

def hash_multiplication(key, table_size):
    """Çarpma yöntemi ile hash hesapla"""
    # Altın oran (golden ratio)
    A = 0.6180339887

    # key × A'nın ondalık kısmını al
    fractional = (key * A) % 1

    # Tablo boyutu ile çarp ve tam kısmı al
    return int(table_size * fractional)

# Örnek kullanım
table_size = 16  # 2'nin kuvveti - multiplication için iyi

keys = [25, 38, 123, 456, 789, 1000]

print(f"Tablo boyutu: {table_size}")
print(f"A sabiti: 0.6180339887 (Altın Oran)")
print()
print(f"{'Anahtar':<10} {'key × A':<15} {'Ondalık':<12} {'Hash':<10}")
print("-" * 47)

for key in keys:
    product = key * 0.6180339887
    fractional = product % 1
    hash_val = hash_multiplication(key, table_size)
    print(f"{key:<10} {product:<15.4f} {fractional:<12.4f} {hash_val:<10}")

# Karşılaştırma: Division vs Multiplication
print("\n=== Division vs Multiplication Karşılaştırma ===")
print(f"{'Anahtar':<10} {'Division':<15} {'Multiplication':<15}")
print("-" * 40)

for key in keys:
    div_hash = key % table_size
    mult_hash = hash_multiplication(key, table_size)
    print(f"{key:<10} {div_hash:<15} {mult_hash:<15}")
Çıktı bekleniyor...

🎲 3. Python'un hash() Fonksiyonu

Python'da yerleşik gelen hash fonksiyonu - çok gelişmiş ve optimize edilmiş!

✨ Python hash() Özellikleri

  • Her veri tipi için özel optimize edilmiş
  • String, int, tuple, frozenset için çalışır
  • List, dict, set için çalışmaz (değiştirilebilir oldukları için)
  • Her Python oturumunda farklı olabilir (güvenlik için)
Python hash() - Örnekler
# Python'un yerleşik hash fonksiyonu

# Sayılar için
print("=== Sayılar ===")
numbers = [1, 42, 123, 1000, -50]
for num in numbers:
    print(f"hash({num:>5}) = {hash(num)}")

# String'ler için
print("\n=== String'ler ===")
words = ["elma", "armut", "muz", "python", "algoritma"]
for word in words:
    print(f"hash('{word:<10}') = {hash(word)}")

# Tuple için (değiştirilemez)
print("\n=== Tuple (çalışır) ===")
my_tuple = (1, 2, 3)
print(f"hash({my_tuple}) = {hash(my_tuple)}")

# Hash table için kullanım
print("\n=== Hash Table Kullanımı ===")
table_size = 10

# String anahtarları hash'le ve tabloya yerleştir
keys = ["elma", "armut", "muz"]
for key in keys:
    hash_value = hash(key)
    index = hash_value % table_size  # Tabloya sığdır
    print(f"'{key}' -> hash: {hash_value:>10} -> indeks: {index}")

# ❌ List için çalışmaz
print("\n=== ❌ List (çalışmaz) ===")
try:
    my_list = [1, 2, 3]
    print(hash(my_list))
except TypeError as e:
    print(f"HATA: {e}")
    print("List değiştirilebilir olduğu için hash'lenemez!")
Çıktı bekleniyor...

⚖️ Hangi Yöntemi Kullanmalı?

Durum Önerilen Yöntem Neden?
Sayısal anahtarlar Division Basit, hızlı, yeterli
String anahtarlar Python hash() Optimize edilmiş, güvenilir
Kötü dağılım Multiplication Daha iyi dağılım sağlar
Eğitim/Öğrenme Division Anlaşılması en kolay
Gerçek projeler Python dict Yerleşik, güvenli, hızlı

💡 Önemli Hatırlatmalar

🎯 Deterministik Olmalı

Aynı anahtar her zaman aynı hash değerini vermelidir!

⚡ Hızlı Olmalı

Hash hesaplama O(1) zamanda olmalı - karmaşık işlemlerden kaçının!

📊 Düzgün Dağıtmalı

Tüm indeksler eşit şansla kullanılmalı - tek bir yerde toplanmamalı!

📋 Özet

✅ Bu Bölümde Öğrendikleriniz

  • Hash fonksiyonu: Anahtarı indekse dönüştürür
  • Division Method: key % table_size (en basit)
  • Multiplication Method: Altın oran kullanır (daha gelişmiş)
  • Python hash(): Yerleşik, optimize edilmiş fonksiyon
  • İyi hash: Hızlı, deterministik, düzgün dağıtan

📚 Sonraki Konu

Hash fonksiyonları bazen aynı indeksi verir - buna çakışma (collision) denir. Bir sonraki bölümde çakışmaları nasıl çözeceğimizi öğreneceğiz!