flowchart LR
A["1. İşlemleri belirle"] --> B["2. Sıklık / maliyet gereksinimini belirle"]
B --> C["3. Yapı veya algoritmayı seç"]
C --> D["Seçimi doğruluk + maliyet ile gerekçelendir"]
Uygun veri yapısı ve algoritma seçimi
Bu derste öğrendiğiniz yapıların hiçbiri tek başına “en iyi” değildir. Liste, sözlük, küme, yığın, kuyruk, doğrusal arama, ikili arama ve sıralama farklı gereksinimlere hizmet eder. Bu hafta yeni bir veri yapısı öğrenmek yerine seçim yapmayı ve seçimi gerekçelendirmeyi çalışacağız.
Aynı zamanda hazır veya AI tarafından üretilmiş bir çözümün yalnızca çalışıp çalışmadığına değil, gereksiz veri yapısı seçimi, yanlış maliyet varsayımı ve ön koşul ihlali açısından da bakacağız.
1 Bu hafta neleri yapabilmelisiniz?
Bölümün sonunda:
- erişim, üyelik, benzersizlik, sıra, güncelleme ve sıralama gereksinimlerini ayırt edebilmeli,
- problem gereksiniminden uygun Python koleksiyonuna geçebilmeli,
- veri yapısı seçimini üç adımlı bir karar yöntemiyle gerekçelendirebilmeli,
- arama yöntemini verinin düzenine ve kullanım sıklığına göre seçebilmeli,
- yığın ve kuyruk arasında işlem sırasına göre karar verebilmeli,
- bir çözümün maliyetini nitel düzeyde gerekçelendirebilmeli,
- çalışan fakat gereksiz veya yanlış yapı kullanan kodu eleştirebilmeli,
- AI üretimi bir çözümde ön koşul ve maliyet hatalarını fark edebilmelisiniz.
2 Seçime problemden başlayın
Yanlış soru:
Bu problemi
dictile yapabilir miyim?
Daha iyi soru:
Program verinin üzerinde en sık hangi işlemleri yapacak ve bu işlemler için hangi kaynak/maliyet sınırları önemli?
Veri yapısı seçimini üç adımda düşünmek yararlıdır.
3 Üç adımlı seçim yöntemi
3.1 1. Gerekli işlemleri belirle
Önce programın ne yapacağını açıkça yazın:
- sırayla dolaşma mı?
- anahtardan kayda erişme mi?
- üyelik kontrolü mü?
- benzersizlik mi?
- ilk geleni önce işleme mi?
- son geleni önce işleme mi?
- sıralı rapor üretme mi?
3.2 2. İşlemlerin önemini ve sıklığını belirle
Aynı işlem bir kez yapılacaksa ve binlerce kez yapılacaksa karar aynı olmak zorunda değildir.
Örneğin:
Bir kez ürün kodu ara → doğrusal arama yeterli olabilir
Her istekte ürün kodu ara → dict ile indekslemek daha anlamlı olabilir
Burada veri boyutu, işlem sıklığı ve ek bellek kullanımı birlikte düşünülür.
3.3 3. Gereksinime en uygun yapıyı seç ve gerekçelendir
Seçim yalnızca “daha hızlı” diye yapılmamalıdır. Yapı, problemin anlamını da korumalıdır.
Daha karmaşık bir veri yapısı otomatik olarak daha iyi değildir. En basit yapı gereksinimleri yeterince karşılıyorsa onu seçmek çoğu zaman daha doğrudur.
4 Temel karar ölçütleri
| Gereksinim | Sık kullanılan seçenek |
|---|---|
| sırayı ve tekrarları koruma | list |
| sabit, değişmeyecek sıralı grup | tuple |
| anahtar → değer ilişkisi | dict |
| benzersizlik | set |
| çok sık üyelik kontrolü | çoğu zaman set / dict |
| son giren önce çıksın | yığın: list / deque |
| ilk giren önce çıksın | kuyruk: deque |
| sıralı veride tekrar eden arama | ikili arama düşünülebilir |
| küçük veya sırasız veride basit arama | doğrusal arama |
| kayıtları ölçüte göre düzenleme | sorted() / .sort() |
Bu tablo otomatik karar vermez. Veri boyutu, mevcut veri düzeni ve yapılan işlemlerin sıklığı da önemlidir.
5 Senaryo 1 — kullanıcı adları
Bir sistem yeni kullanıcı adı eklenirken adın daha önce kullanılıp kullanılmadığını kontrol ediyor. Sıra önemli değil; benzersizlik önemli.
usernames = {"ada", "mert", "ece"}
if "ada" in usernames:
print("Kullanılıyor")Üç adımlı gerekçe:
- Temel işlem: üyelik kontrolü ve benzersizlik.
- İşlem sık yapılacak.
set, hem anlamı doğrudan temsil eder hem de ortalama durumda hızlı üyelik kontrolü sağlar.
Liste de çalışabilir:
usernames = ["ada", "mert", "ece"]ancak tekrar eden çok sayıda üyelik kontrolü için daha zayıf bir seçim olabilir.
6 Senaryo 2 — öğrenci sırası
Bir sınıftaki öğrencilerin kayıt sırası korunacak ve aynı isim birden çok kez bulunabilir. Burada set veri kaybına yol açabilir:
#| edit: false
#| completion: false
names = ["Ada", "Mert", "Ada", "Ece"]
print("Liste:", names)
print("Küme:", set(names))
Küme tekrarları kaldırdığı için problem anlamını değiştirir. “Daha hızlı” olması, onu otomatik olarak doğru yapı yapmaz.
7 Senaryo 3 — ürün kodundan ürüne erişim
#| edit: false
#| completion: false
products = {
"K101": {"name": "Kalem", "stock": 20},
"D205": {"name": "Defter", "stock": 8},
}
print(products["D205"])
Anahtar tabanlı erişim gereksinimi sözlükle doğal biçimde ifade edilir.
8 Senaryo 4 — undo ve müşteri sırası
Aynı “eleman ekle ve çıkar” problemi iki farklı sıraya sahip olabilir:
Undo geçmişi → son yapılan önce geri alınır → LIFO → yığın
Müşteri kuyruğu → ilk gelen önce işlenir → FIFO → kuyruk
Burada veri türleri aynı olsa bile işlem sırası veri modelini belirler.
9 Arama seçimi
Arama kararında şu soruları sorun:
- Veri sıralı mı?
- Kaç kez arama yapılacak?
- Arama ölçütüne göre farklı bir indeks oluşturmak mümkün mü?
- İndeks oluşturmanın bellek ve kurulum maliyeti kabul edilebilir mi?
9.1 Bir kez arama
Sırasız küçük listede doğrusal arama yeterli olabilir.
9.2 Çok sayıda arama
Aynı anahtara göre tekrar tekrar arama yapılıyorsa:
- veriyi sözlükle indekslemek,
- veya veri zaten sıralıysa ikili arama kullanmak
anlamlı olabilir.
10 Sıralama her zaman gerekli mi?
“En küçük öğeyi bul” problemi için bütün listeyi sıralamak zorunda değiliz:
#| edit: false
#| completion: false
values = [18, 4, 27, 2, 11]
print("min:", min(values))
print("sorted ilk:", sorted(values)[0])
İki sonuç aynı olabilir; ancak yapılan iş aynı değildir. Sadece minimum gerekiyorsa tüm veriyi sıralamak gereksiz olabilir.
Gereksinim “en küçük öğe” ise çözümü “tam sıralama” problemi hâline getirmeyin.
11 Karar akışı
flowchart TD
A["Gereksinimi belirle"] --> B{"Anahtardan değere erişim?"}
B -- Evet --> C["dict düşün"]
B -- Hayır --> D{"Benzersizlik / sık üyelik?"}
D -- Evet --> E["set düşün"]
D -- Hayır --> F{"Öğe çıkarma sırası önemli mi?"}
F -- Son giren önce --> G["stack"]
F -- İlk giren önce --> H["queue / deque"]
F -- Hayır --> I{"Sıralı dizi üzerinde arama?"}
I -- Evet --> J["binary search düşünülebilir"]
I -- Hayır --> K["list + linear processing"]
Bu şema başlangıç için yardımcıdır; gerçek problemler birden çok yapıyı birlikte kullanabilir.
12 Aynı programda birden çok yapı
Bir e-ticaret uygulamasında:
- ürünlerin gösterim sırası için
list, - ürün kodundan erişim için
dict, - kullanılmış kupon kodları için
set, - işlenecek siparişler için
deque
aynı anda bulunabilir. İyi tasarım, “tek veri yapısı seçmek” değil; her gereksinime uygun yapı kombinasyonu kurmaktır.
13 Çalışan ama zayıf çözüm 1
Aşağıdaki kod, yasaklı kullanıcı adını bulmak için her sorguda liste dolaşıyor:
#| edit: false
#| completion: false
blocked = ["bot1", "spam2", "fake3", "bot4", "spam5"]
def is_blocked(username):
return username in blocked
for username in ["ada", "bot4", "ece"]:
print(username, is_blocked(username))
Beş elemanda sorun görünmez. Ancak yüz binlerce isim ve çok sayıda sorgu varsa, set daha uygun olabilir:
blocked = {"bot1", "spam2", "fake3", "bot4", "spam5"}Burada değiştirdiğimiz şey programın dış davranışı değil, veri yapısı seçimidir.
14 Çalışan ama zayıf çözüm 2
queue = []
queue.append("A")
queue.append("B")
current = queue.pop(0)Bu kod FIFO açısından doğrudur. Ancak çok büyük ve yoğun bir kuyrukta deque.popleft() daha uygun olacaktır.
15 Çalışmayan varsayım: sırasız veride ikili arama
Şu “AI önerisi” verildiğini düşünün:
def fast_search(values, target):
low = 0
high = len(values) - 1
while low <= high:
mid = (low + high) // 2
if values[mid] == target:
return mid
if target < values[mid]:
high = mid - 1
else:
low = mid + 1
return -1Fonksiyonun kendisi standart ikili aramaya benziyor. Fakat kullanıcı bu fonksiyona şu veriyi gönderiyor:
values = [50, 3, 90, 12, 40]Sorun kodun sözdiziminde değil, ön koşulun eksik olmasındadır. Veri sıralı değilse ikili aramanın kararları geçersizdir.
AI veya insan tarafından üretilen kodu değerlendirirken yalnızca “çalışıyor mu?” sorusunu sormayın. Hangi ön koşullarda doğru? sorusunu da sorun.
16 AI çıktısını inceleme kontrol listesi
Bir veri yapısı/algoritma önerisini şu sorularla inceleyin:
- Problem gereksinimi doğru anlaşılmış mı?
- Veri sırası veya benzersizlik gereksinimi korunuyor mu?
- Algoritmanın ön koşulu sağlanıyor mu?
- Gereksiz sıralama, kopyalama veya dönüştürme var mı?
- Sık yapılan işlem için uygun koleksiyon kullanılmış mı?
- Boş veri, bulunamama ve tekrar gibi sınır durumları düşünülmüş mü?
- Daha basit bir çözüm aynı işi yapabilir mi?
- Daha hızlı görünen çözüm ek bellek veya kurulum maliyeti oluşturuyor mu?
17 Alıştırma — veri yapısını düzelt
Aşağıdaki fonksiyon, yüz binlerce kayıtta çok sık üyelik kontrolü yapılan bir sistemi temsil ediyor. allowed verisini ve fonksiyonu uygun biçimde düzenleyin. Fonksiyonun dış davranışı değişmemelidir.
#| exercise: hafta13-membership
#| completion: false
#| persist: true
allowed = ["python", "data", "web", "network", "linux"]
def is_allowed(tag):
return tag in allowed
print(is_allowed("data"))
print(is_allowed("java"))
#| exercise: hafta13-membership
#| check: true
scope = {}
try:
exec(user_code, scope)
fn = scope.get("is_allowed")
allowed = scope.get("allowed")
correct = (
callable(fn)
and isinstance(allowed, set)
and fn("data") is True
and fn("java") is False
)
except Exception:
correct = False
feedback = (
{"correct": True, "message": "Üyelik ağırlıklı gereksinim için set seçildi ve davranış korundu."}
if correct
else {"correct": False, "message": "allowed verisini set olarak temsil edin; is_allowed aynı üyelik kontrolünü kullanabilir."}
)
feedback
Köşeli parantez yerine küme sözdizimini kullanın: {"python", ...}.
Solution.
allowed = {"python", "data", "web", "network", "linux"}
def is_allowed(tag):
return tag in allowed18 Alıştırma — üç adımlı seçim gerekçesi
Bir çağrı merkezinde gelen talepler geliş sırasıyla işlenecek. Sistem aynı anda yaklaşık 50.000 bekleyen talep tutabilir ve her işlemde sıradaki talep baştan çıkarılacak.
Aşağıdaki taslağı tamamlayın:
1. Temel işlem(ler): ______________________________
2. Sıklık / maliyet gereksinimi: __________________
3. Seçim: _________________________________________
Gerekçe: __________________________________________
Beklenen teknik gerekçede şu unsurlar bulunmalıdır:
- FIFO davranışı,
- baştan sık çıkarma,
dequevepopleft(),list.pop(0)işleminin O(n) sezgisi.
19 Gerekçelendirme dili
“set daha iyi” demek yerine daha teknik ve ölçülebilir bir gerekçe yazın:
Kullanıcı adlarının sırası ve tekrarları önemli değil; temel işlem üyelik kontrolü. Bu nedenle
set, listeye göre gereksinimi daha doğrudan temsil eder ve ortalama üyelik kontrolü maliyeti açısından daha uygundur.
Benzer şekilde:
Veri zaten sıralı ve aynı liste üzerinde çok sayıda arama yapılacak. Bu nedenle O(n) doğrusal arama yerine O(log n) sezgisine sahip ikili arama uygundur.
Bu ders için kısa ama işlem gereksinimi + yapı/algoritma + maliyet üçlüsünü içeren gerekçe yeterlidir.
20 Kısa senaryo çalışması
Her senaryo için üç adımlı yöntemi kullanarak yapı/algoritma seçin ve bir cümle gerekçe yazın:
- Son 20 hata mesajını geliş sırasına göre tutmak; yeni mesaj geldikçe en eskisi atılacak.
- Bir kitap ISBN’sinden kitap kaydına çok sık ulaşmak.
- Kullanılmış davet kodlarının tekrar kullanımını engellemek.
- Sırasız 30 elemanlı listede bir kez hedef aramak.
- Sıralı 500.000 kimlik üzerinde çok sayıda arama yapmak.
- Her işlemde en son eklenen düzenleme adımını geri almak.
21 Bölüm özeti
- Veri yapısı seçimi problem gereksiniminden başlamalıdır.
- Sistematik seçim için üç adım kullanılabilir: işlemleri belirle → sıklık/maliyet gereksinimini belirle → yapıyı seç ve gerekçelendir.
- Daha karmaşık veri yapısı otomatik olarak daha iyi değildir.
- Sıra, benzersizlik, erişim biçimi ve çıkarma sırası semantik gereksinimlerdir; yalnızca performans ayrıntısı değildir.
- Arama yöntemi verinin sıralı olup olmamasına ve arama sıklığına bağlıdır.
- Çalışan bir çözüm, uygun veri yapısı kullandığını garanti etmez.
- Algoritmanın ön koşulları mutlaka kontrol edilmelidir.
- AI üretimi kod da aynı doğruluk, ön koşul, sınır durumu ve maliyet ölçütleriyle değerlendirilmelidir.
22 Kendinizi kontrol edin
- Veri yapısı seçiminin üç adımı nelerdir?
- Neden “en hızlı veri yapısı” diye tek bir doğru cevap yoktur?
sethangi semantik gereksinimleri doğrudan temsil eder?- Çok sık kimlik araması için
dictindeksi ne kazandırır ve ne tür ek maliyet getirir? dequeile normal liste arasında kuyruk bağlamındaki temel maliyet farkı nedir?- İkili arama önerisinde hangi ön koşulu mutlaka doğrulamak gerekir?
- Bir AI çözümünü incelerken yalnızca çıktının doğru olması neden yeterli değildir?