Bu sayfa bir yazıdan çok bir depo. Bilimsel değerlendirme sınavına çalışırken dağınık duran notlarımı, kod örneklerini, karşılaştırma tablolarını ve en önemlisi “neden böyle?” sorularının cevaplarını tek yerde topladım. Amacım listeyi ezberlemek değil, her maddenin arkasındaki gerekçeyi cümleye dökebilmekti — çünkü sınavlar tanımı değil gerekçeyi soruyor.
Konu başlıklarının yanındaki sık sorulur rozeti, geçmiş sınavlarda tekrar tekrar karşıma çıkan başlıkları işaretliyor. tuzak ise yanlış cevaplaması kolay olanları.
Bölüm 1 — Yazılım Geliştirme Süreçleri
SDLC (Software Development Life Cycle)
Bir yazılımın fikir aşamasından kullanımdan kaldırılmasına kadar geçen tüm süreçleri kapsayan modeldir. Amacı; süreci adımlara bölerek kaliteyi artırmak, maliyeti düşürmek ve süreci yönetilebilir kılmaktır.
Planlama (Planning)
Proje hedefleri, kapsam, bütçe ve kaynaklar belirlenir. “Bu işi yapmalı mıyız?” sorusunun cevaplandığı yer.
Analiz (Analysis)
Mevcut sistem incelenir, kullanıcı ihtiyaçları detaylandırılır. Fonksiyonel ve fonksiyonel olmayan gereksinimler burada çıkarılır.
Tasarım (Design)
Mimari, modüller, arayüzler ve veri yapıları tasarlanır. Kod yazılmadan önceki son karar noktası.
Geliştirme (Implementation)
Tasarım koda dökülür.
Test (Testing)
Hatalar bulunur, gereksinimlerin karşılanıp karşılanmadığı kontrol edilir.
Dağıtım (Deployment)
Yazılım son kullanıcıya sunulur.
Bakım (Maintenance)
Canlıdaki hatalar giderilir, güncellemeler yapılır. Genelde en uzun ve en pahalı aşama budur.
flowchart LR
A[Planlama] --> B[Analiz] --> C[Tasarım] --> D[Geliştirme] --> E[Test] --> F[Dağıtım] --> G[Bakım]Waterfall ve Scrum
Waterfall (Şelale)
Geleneksel modeldir. Her aşama, bir sonrakine geçilmeden tamamen bitirilir; geri dönüş zordur ve pahalıdır.
Ne zaman uygun? Gereksinimlerin baştan net olduğu ve değişmeyeceği projelerde — savunma sanayii, regülasyon ağırlıklı işler.
Scrum (Agile)
Proje, Sprint adı verilen kısa döngülerle (genellikle 2–4 hafta) geliştirilir. Her sprint sonunda çalışan bir ürün çıkar.
Ne zaman uygun? Değişime açık, müşteriyle sürekli iletişim gerektiren projelerde.
Scrum rolleri: Product Owner (ürün sahibi — backlog’u önceliklendirir), Scrum Master (süreci kolaylaştırır, engelleri kaldırır), Development Team.
Scrum etkinlikleri: Sprint Planning, Daily Scrum (günlük 15 dk), Sprint Review, Sprint Retrospective.
Fonksiyonel ve Fonksiyonel Olmayan Gereksinimler
| Fonksiyonel | Fonksiyonel Olmayan | |
|---|---|---|
| Neyi tanımlar | Sistemin ne yapması gerektiğini | Sistemin nasıl çalışması gerektiğini |
| Alan | Davranış, özellik | Performans, güvenlik, kullanılabilirlik, kalite |
| Örnek | “Kullanıcı e-posta ve şifre ile giriş yapabilmelidir.” | “Sistem aynı anda 1000 kullanıcıyı kaldırmalı”, “Sayfa 2 saniyede yüklenmeli.” |
Bölüm 2 — Veri Yapıları
Array (Dizi)
Elemanların ardışık bellekte tutulduğu veri yapısıdır. Boyutu genellikle sabittir.
| İşlem | Karmaşıklık | Neden |
|---|---|---|
| İndeks ile erişim | O(1) | Adres = başlangıç + indeks × eleman boyutu; tek hesapla bulunur |
| Arama (sırasız) | O(n) | Baştan sona bakmak gerekir |
| Arama (sıralı, binary search) | O(log n) | Her adımda yarısı elenir |
| Ortadan ekleme/silme | O(n) | Sonrasındaki tüm elemanların kaydırılması gerekir |
Linked List (Bağlı Liste)
Her elemanın (node) veriyle birlikte bir sonraki node’un referansını tuttuğu dinamik yapıdır. Bellekte ardışık durmak zorunda değildir.
- Arama / belirli node’a erişim: O(n)
- Bilinen bir node’dan ekleme/silme: O(1) (sadece referanslar değişir)
- Türleri: tek yönlü (singly), çift yönlü (doubly), dairesel (circular)
Array vs Linked List — tek cümlede: Array hızlı erişim (O(1) indeks) sunar ama boyutu sabittir ve ortadan ekleme pahalıdır; Linked List dinamik büyür ve ekleme/silme ucuzdur ama indeksle doğrudan erişim yoktur — ayrıca her node için ek referans belleği harcar ve elemanlar bellekte dağınık olduğu için cache locality kötüdür.
Stack ve Queue
Stack (Yığın) — LIFO
Last In, First Out: Son giren ilk çıkar.
push (ekle), pop (çıkar), peek (üsttekine bak) — hepsi O(1).
Nerede: tarayıcı geri butonu, fonksiyon çağrı yığını (call stack), undo işlemi, parantez denetimi, DFS.
Queue (Kuyruk) — FIFO
First In, First Out: İlk giren ilk çıkar.
enqueue (sona ekle), dequeue (baştan çıkar) — O(1).
Nerede: yazıcı kuyruğu, process scheduling, mesaj kuyrukları, BFS.
flowchart LR
subgraph Stack [Stack - LIFO]
direction TB
S3[3 - en son giren, ilk çıkar] --- S2[2] --- S1[1]
end
subgraph Queue [Queue - FIFO]
direction LR
Q1[1 - ilk giren, ilk çıkar] --- Q2[2] --- Q3[3]
endStack uygulaması: parantez denetimi klasik soru
Stack’in “neden LIFO?” sorusunun en somut cevabı bu. Bir ifadedeki parantezlerin doğru kapanıp kapanmadığını kontrol ederken, en son açılan parantezin ilk kapanması gerekir — yani tam olarak yığın davranışı.
def parantez_dogru_mu(s):
stack = []
eslesme = {
')': '(',
']': '[',
'}': '{'
}
for ch in s:
if ch in "([{":
stack.append(ch) # açılış → yığına at
elif ch in ")]}":
if not stack: # kapanış geldi ama açık parantez yok
return False
if stack.pop() != eslesme[ch]: # en son açılanla türü uyuşmuyor
return False
return len(stack) == 0 # sonda yığın boşsa hepsi kapanmış
print(parantez_dogru_mu("{[()]}")) # True
print(parantez_dogru_mu("{[(])}")) # False
print(parantez_dogru_mu("([]{})")) # True
print(parantez_dogru_mu("([)]")) # False
Üç ayrı False durumu var — sınavda “hangi durumda neden reddedilir?” diye sorulabiliyor:
| Durum | Örnek | Nerede yakalanır |
|---|---|---|
| Fazla kapanış | "())" | if not stack — yığın boşken kapanış geldi |
| Yanlış türde kapanış | "([)]" | stack.pop() != eslesme[ch] — açılan [ iken ) geldi |
| Fazla açılış | "(()" | len(stack) == 0 — döngü bitti ama yığında artık kaldı |
"([)]" adım adım — sezgiye ters gelen, en öğretici örnek:
| Adım | Karakter | İşlem | Stack (alt → üst) | Sonuç |
|---|---|---|---|---|
| 1 | ( | push | [ ( ] | devam |
| 2 | [ | push | [ (, [ ] | devam |
| 3 | ) | pop → [ , beklenen ( | [ ( ] | False — tür uyuşmadı |
Parantez sayıları eşit ((×1, )×1, [×1, ]×1) ama iç içe geçme sırası bozuk. Sadece sayarak çözmeye çalışan bir yaklaşım bunu kaçırır; stack yakalar.
Neden sayaç yetmez, stack gerekir?
Tek tür parantez varsa (( ve )) basit bir sayaç yeterlidir: açılışta artır, kapanışta azalt, negatife düşerse veya sonda sıfır değilse hatalı. Ama birden fazla tür olduğu anda sayaç çöker — "([)]" örneğinde her sayaç dengeli görünür.
Stack, “en son hangi türü açtım?” bilgisini sakladığı için sırayı da doğrular. Karmaşıklık: zaman O(n), bellek O(n) (en kötü durumda hepsi açılış: "(((((").
Bu problem, Chomsky hiyerarşisi bölümüyle doğrudan bağlantılı: dengeli parantez dili context-free‘dir (Tip 2) ve tanınması için tam olarak bir stack gerekir. Sonlu otomat (regex) bunu yapamaz — çünkü kaç parantez açıldığını hatırlayacak belleği yoktur. Sınavda “regex ile HTML neden parse edilmez?” sorusunun cevabı da aynı yere çıkıyor.
Hash Table
Anahtar-değer (key-value) mantığıyla çalışır. Bir hash fonksiyonu anahtarı dizide bir indekse dönüştürür.
- Ortalama arama / ekleme / silme: O(1), en kötü durum: O(n)
- Collision (çakışma): İki farklı anahtar aynı indekse düşerse oluşur. Çözümler: chaining (aynı hücrede bağlı liste) veya open addressing (bir sonraki boş hücreyi arama).
Neden HashMap O(1)?
Çünkü anahtar, hash fonksiyonuyla doğrudan bir dizi indeksine dönüştürülür; arama yapılmaz, doğrudan o hücreye gidilir. Çakışmalar azsa erişim sabit zamandır. Çakışma çok olursa aynı hücredeki zincir uzar ve en kötü durumda O(n)’e düşer — bu yüzden iyi bir hash fonksiyonu ve makul bir load factor önemlidir.
Tree (Ağaç) ve Binary Search Tree (BST)
Hiyerarşik veri yapısıdır. En üstteki düğüm root (kök), çocuğu olmayan düğümler leaf (yaprak)’tır.
BST kuralı: Sol alt ağaç < node < Sağ alt ağaç
- Dengeli BST’de arama/ekleme/silme: O(log n)
- Dengesizleşirse (tek kola uzarsa): O(n)
Terimler
| Terim | Anlamı |
|---|---|
| Root (Kök) | En üstteki, ebeveyni olmayan düğüm |
| Leaf (Yaprak) | Hiç çocuğu olmayan düğüm |
| Parent / Child | Üst düğüm / alt düğüm |
| Sibling (Kardeş) | Aynı ebeveyne sahip düğümler |
| Subtree (Alt ağaç) | Bir düğüm ve altındaki her şey |
| Depth (Derinlik) | Kökten o düğüme kadar olan kenar sayısı |
| Height (Yükseklik) | Bir düğümden en derin yaprağa olan kenar sayısı; ağacın yüksekliği = kökün yüksekliği |
| Degree (Derece) | Bir düğümün çocuk sayısı (binary tree’de en fazla 2) |
- Binary Tree: Her düğümün en fazla 2 çocuğu vardır.
- Binary Search Tree (BST): Binary tree + sıralama kuralı (sol < kök < sağ).
- Balanced Tree (Dengeli Ağaç): Sol ve sağ yüksekliklerin farkı sınırlıdır → AVL, Red-Black Tree. Amaç yüksekliği \(\log n\)‘de tutmaktır.
Verilen sayıları ağaca çevirme (BST kurma) klasik soru
Kural: İlk sayı kök olur. Sonraki her sayı kökten başlar; küçükse sola, büyükse sağa iner ve boş bulduğu yere yerleşir. Eşit değerler genelde yok sayılır.
Girdi: 8, 3, 10, 1, 6, 14, 4, 7, 13
| # | Sayı | İzlenen yol | Sonuç |
|---|---|---|---|
| 1 | 8 | — | Kök olur |
| 2 | 3 | 3 < 8 → sol | 8’in soluna |
| 3 | 10 | 10 > 8 → sağ | 8’in sağına |
| 4 | 1 | 1 < 8 → sol(3); 1 < 3 → sol | 3’ün soluna |
| 5 | 6 | 6 < 8 → sol(3); 6 > 3 → sağ | 3’ün sağına |
| 6 | 14 | 14 > 8 → sağ(10); 14 > 10 → sağ | 10’un sağına |
| 7 | 4 | 4 < 8 → 3; 4 > 3 → 6; 4 < 6 → sol | 6’nın soluna |
| 8 | 7 | 7 < 8 → 3; 7 > 3 → 6; 7 > 6 → sağ | 6’nın sağına |
| 9 | 13 | 13 > 8 → 10; 13 > 10 → 14; 13 < 14 → sol | 14’ün soluna |
Oluşan ağaç:
8
/ \
3 10
/ \ \
1 6 14
/ \ /
4 7 13
flowchart TD
A((8)) --> B((3))
A --> C((10))
B --> D((1))
B --> E((6))
E --> F((4))
E --> G((7))
C --> H((14))
H --> I((13))Sınavda tuzak
Ağacın şekli sayıların geliş sırasına bağlıdır. Aynı sayılar sıralı gelirse (1, 3, 4, 6, 7, 8, 10, 13, 14) ağaç tek kola uzar, bağlı listeye döner ve arama O(n) olur. Bu yüzden AVL / Red-Black gibi kendini dengeleyen ağaçlar kullanılır.
Aynı sayıdan birden fazla gelirse ne olur? tuzak
Kısa cevap: Klasik BST tanımında eklenmez. Standart BST kuralı sol < kök < sağ şeklinde kesin eşitsizlik kullanır; eşitlik durumu tanımsızdır. Bu yüzden cevap hangi stratejiyi seçtiğinize bağlıdır.
Aşağıdaki üç yöntemin hepsi, yukarıdaki ağaca iki tane daha 3 geldiği varsayımıyla anlatılıyor.
Değer zaten varsa hiçbir şey yapılmaz; ağaç değişmez. Bu, Set (küme) davranışıdır ve sınavlarda varsayılan kabul edilen cevaptır.
if value < root.value: root.left = insert(root.left, value)
elif value > root.value: root.right = insert(root.right, value)
# eşitse: hiçbir şey yapma → sessizce yok sayılır
- Ağaç: Değişmez. İçinde tek bir
3kalır. - Java’da
TreeSet.add(), C++‘tastd::set::insert()bu şekilde davranır.
Düğüme bir count alanı eklenir; tekrar gelen değer yeni düğüm açmaz, sayacı artırır. Pratikte en doğru çözüm budur.
class Node:
def __init__(self, value):
self.value = value
self.count = 1 # ← kaç kez eklendi
self.left = self.right = None
def insert(root, value):
if root is None: return Node(value)
if value < root.value: root.left = insert(root.left, value)
elif value > root.value: root.right = insert(root.right, value)
else: root.count += 1 # ← tekrar
return root
- Ağaç: Düğüm sayısı değişmez,
3düğümünün sayacıcount = 3olur. - Avantajı: Ağaç şişmez, dengesi bozulmaz, arama O(log n) kalır.
Map<değer, adet>(multiset) davranışı.
Kural sol < kök ≤ sağ (veya sol ≤ kök < sağ) olarak gevşetilir. Tutarlılık şarttır — bazı tekrarları sola bazılarını sağa koyarsanız arama bozulur.
Eşitleri sağa koyma kuralıyla ikinci 3‘ün izlediği yol:
8'de: 3 < 8 → sola
3'te: 3 < 3 değil → SAĞA
6'da: 3 < 6 → sola
4'te: 3 < 4 → sola → boş! Buraya yerleşir.
Üçüncü 3 de aynı yolu izler, sonunda ikinci 3‘ün sağına yerleşir:
8
/ \
3 10
/ \ \
1 6 14
/ \ /
4 7 13
/
3(2) ← ikinci 3
\
3(3) ← üçüncü 3
- Kritik gözlem: Inorder dolaşma hâlâ sıralı çıkar →
1, 3, 3, 3, 4, 6, 7, 8, 10, 13, 14✓ Yani BST özelliği bozulmaz. - Dezavantajı: Aynı değerden çok gelirse ağaç derinleşir ve dengesizleşir; arama O(n)’e kayabilir. Ayrıca silme işlemi karmaşıklaşır — hangi kopyayı sileceksin?
| Yöntem | Düğüm sayısı | Ağaç dengesi | Kullanım |
|---|---|---|---|
| Yok say | Artmaz | Bozulmaz | Set (küme) semantiği; sınav varsayılanı |
| Sayaç tut | Artmaz | Bozulmaz | Önerilen — multiset / frekans sayımı |
| Sağa/sola koy | Artar | Bozulabilir | Sıralamanın kararlılığı (stability) gerektiğinde |
Sınavda söylenecek cevap
“Klasik BST tanımı tekrarlı değere izin vermez, çünkü kural kesin eşitsizliktir; varsayılan davranış değeri yok saymaktır. Tekrarları saklamak gerekiyorsa en temiz çözüm düğümde bir sayaç (count) tutmaktır. Alternatif olarak eşitler tutarlı biçimde hep aynı tarafa (örn. sağa) konulabilir — bu durumda inorder yine sıralı çıkar ama ağaç dengesizleşme riski taşır.”
Diğer yapılarda durum: Heap’te ve normal binary tree‘de (arama ağacı değil) tekrarlı değerler tamamen serbesttir, hiçbir kural bozulmaz. Sorun yalnızca sıralama kuralı olan BST’ye özgüdür. Aynı şekilde HashSet tekrarı yok sayar, HashMap.put() eski değeri ezer.
Ağaç Dolaşma (Tree Traversal) — DFS ve BFS sık sorulur
Ağacın tüm düğümlerini gezme yöntemleridir. İkiye ayrılır:
- DFS (Depth-First Search — Derinlik Öncelikli): Bir kolun sonuna kadar iner, sonra geri döner. Stack veya recursion kullanır. Üç çeşidi vardır: Preorder, Inorder, Postorder.
- BFS (Breadth-First Search — Genişlik Öncelikli): Ağacı seviye seviye gezer. Queue (kuyruk) kullanır. Ağaçlardaki adı Level-order traversal‘dır.
DFS’in üç çeşidi — aralarındaki tek fark, kökün ne zaman yazıldığıdır. Sol her zaman sağdan önce gelir.
| Dolaşma | Sıra | Ezber cümlesi |
|---|---|---|
| Preorder (Kök öncelikli) | Kök → Sol → Sağ | Kök önce |
| Inorder (Sıralı) | Sol → Kök → Sağ | Kök ortada |
| Postorder (Kök sonda) | Sol → Sağ → Kök | Kök sonra |
| Level-order (BFS) | Seviye seviye, soldan sağa | Katman katman |
İsimlendirme mantığı
“pre / in / post” ekleri, kökün çocuklarına göre nerede yazıldığını söyler. Sol her zaman sağdan önce gelir; değişen tek şey kökün yeridir.
PREorder = kök ÖNCE →
K S SğINorder = kök ORTADA →
S K SğPOSTorder = kök SONRA →
S Sğ K
Yukarıdaki 8, 3, 10, 1, 6, 14, 4, 7, 13 ağacı için çıktılar (ezberlemeyin, elle çıkarın):
Preorder (Kök-Sol-Sağ) : 8, 3, 1, 6, 4, 7, 10, 14, 13
Inorder (Sol-Kök-Sağ) : 1, 3, 4, 6, 7, 8, 10, 13, 14 ← SIRALI!
Postorder (Sol-Sağ-Kök) : 1, 4, 7, 6, 3, 13, 14, 10, 8
Level-order (BFS) : 8, 3, 10, 1, 6, 14, 4, 7, 13
En kritik bilgi
Bir BST‘yi inorder dolaşırsanız sayılar küçükten büyüğe sıralı çıkar. “Ağacı sıralı yazdır” sorusunun cevabı budur. Tersten sıralı isteniyorsa: Sağ → Kök → Sol.
Dolaşmayı elle çıkarmanın dört yolu
Aşağıdaki dört yöntem de aynı sonucu verir; sınavda hangisi hızınıza uyuyorsa onu kullanın.
Bu, sınavda saniyeler içinde üç dolaşmayı birden çıkarmanızı sağlar.
Kural: Kalemi kökün sol üstünden başlatıp, ağacın dış çeperini takip ederek kesintisiz bir çizgi çizin (saat yönünün tersine). Bu yolda her düğümün yanından tam 3 kez geçersiniz:
┌─── 1. geçiş: düğümün SOLUNDAN (aşağı inerken) → PREORDER'a yaz
│
╭───┴───╮
─────┤ DÜĞÜM ├─────
╰───┬───╯ └─ 3. geçiş: düğümün SAĞINDAN (yukarı çıkarken) → POSTORDER'a yaz
│
└─── 2. geçiş: düğümün ALTINDAN (sol bitip sağa geçerken) → INORDER'a yaz
| Kaçıncı geçiş | Nereden geçilir | Hangi listeye yazılır |
|---|---|---|
| 1. | Sol yanından (düğüme ilk varış) | Preorder |
| 2. | Alt tarafından (sol alt ağaç bitti, sağa geçiliyor) | Inorder |
| 3. | Sağ yanından (düğümün işi tamamen bitti) | Postorder |
Yani tek bir gezinti üç çıktıyı birden verir. Yaprak düğümlerde üç geçiş art arda olur (soluna, altına, sağına).
Aynı ağaç, her düğümün kaçıncı sırada yazıldığı üst simge olarak eklenmiş hâlde:
PREORDER (Kök-Sol-Sağ) INORDER (Sol-Kök-Sağ) POSTORDER (Sol-Sağ-Kök)
8⁽¹⁾ 8⁽⁶⁾ 8⁽⁹⁾
/ \ / \ / \
3⁽²⁾ 10⁽⁷⁾ 3⁽²⁾ 10⁽⁷⁾ 3⁽⁵⁾ 10⁽⁸⁾
/ \ \ / \ \ / \ \
1⁽³⁾ 6⁽⁴⁾ 14⁽⁸⁾ 1⁽¹⁾ 6⁽⁴⁾ 14⁽⁹⁾ 1⁽¹⁾ 6⁽⁴⁾ 14⁽⁷⁾
/ \ / / \ / / \ /
4⁽⁵⁾ 7⁽⁶⁾ 13⁽⁹⁾ 4⁽³⁾ 7⁽⁵⁾ 13⁽⁸⁾ 4⁽²⁾ 7⁽³⁾ 13⁽⁶⁾
Kök hep EN BAŞTA (1) Kök hep ORTADA (6) Kök hep EN SONDA (9)
→ yukarıdan aşağı → soldan sağa → aşağıdan yukarı
Sezgisel özet:
- Preorder → yukarıdan aşağıya, sola yaslanarak (ağacı “yukarıdan” okur)
- Inorder → ağacı düzleştirip soldan sağa okur (yatay projeksiyon)
- Postorder → aşağıdan yukarıya, yapraklardan köke doğru (ağacı “sökerek” okur)
Üç fonksiyon birebir aynıdır; tek fark yaz() satırının yeri:
def preorder(n): def inorder(n): def postorder(n):
if n is None: return if n is None: return if n is None: return
yaz(n) # ① inorder(n.left) postorder(n.left)
preorder(n.left) yaz(n) # ② postorder(n.right)
preorder(n.right) inorder(n.right) yaz(n) # ③
Preorder adım adım (girinti = recursion derinliği):
pre(8) → YAZ 8 çıktı: 8
pre(3) → YAZ 3 çıktı: 8,3
pre(1) → YAZ 1 çıktı: 8,3,1
pre(None) → dön ; pre(None) → dön
← 1 bitti
pre(6) → YAZ 6 çıktı: 8,3,1,6
pre(4) → YAZ 4 çıktı: 8,3,1,6,4
pre(7) → YAZ 7 çıktı: 8,3,1,6,4,7
← 6 bitti
← 3 bitti
pre(10) → YAZ 10 çıktı: ...,10
pre(None) → dön (10'un solu yok)
pre(14) → YAZ 14 çıktı: ...,14
pre(13) → YAZ 13 çıktı: ...,13
Sonuç: 8, 3, 1, 6, 4, 7, 10, 14, 13
Inorder adım adım — dikkat: düğüm, solu tamamen bitmeden yazılmaz:
in(8)
in(3)
in(1) → solu yok → YAZ 1 → sağı yok çıktı: 1
YAZ 3 çıktı: 1,3
in(6)
in(4) → YAZ 4 çıktı: 1,3,4
YAZ 6 çıktı: 1,3,4,6
in(7) → YAZ 7 çıktı: 1,3,4,6,7
YAZ 8 ← kök tam ortada çıktı: ...,8
in(10)
solu yok → YAZ 10 çıktı: ...,10
in(14)
in(13) → YAZ 13 çıktı: ...,13
YAZ 14 çıktı: ...,14
Sonuç: 1, 3, 4, 6, 7, 8, 10, 13, 14 — tam sıralı ✓
Postorder adım adım — düğüm, hem solu hem sağı bitmeden yazılmaz:
post(8)
post(3)
post(1) → YAZ 1 çıktı: 1
post(6)
post(4) → YAZ 4 çıktı: 1,4
post(7) → YAZ 7 çıktı: 1,4,7
YAZ 6 çıktı: 1,4,7,6
YAZ 3 çıktı: 1,4,7,6,3
post(10)
post(14)
post(13) → YAZ 13 çıktı: ...,13
YAZ 14 çıktı: ...,14
YAZ 10 çıktı: ...,10
YAZ 8 ← kök EN SONDA çıktı: ...,8
Sonuç: 1, 4, 7, 6, 3, 13, 14, 10, 8
Kuyruğa kök atılır; her turda baştan bir düğüm çıkarılır, çocukları sona eklenir.
| Adım | Kuyruk (baş → son) | Çıkarılan | Eklenenler | Çıktı |
|---|---|---|---|---|
| 0 | [8] | — | — | — |
| 1 | [8] | 8 | 3, 10 | 8 |
| 2 | [3, 10] | 3 | 1, 6 | 8, 3 |
| 3 | [10, 1, 6] | 10 | 14 | 8, 3, 10 |
| 4 | [1, 6, 14] | 1 | — | 8, 3, 10, 1 |
| 5 | [6, 14] | 6 | 4, 7 | 8, 3, 10, 1, 6 |
| 6 | [14, 4, 7] | 14 | 13 | …, 14 |
| 7 | [4, 7, 13] | 4 | — | …, 4 |
| 8 | [7, 13] | 7 | — | …, 7 |
| 9 | [13] | 13 | — | …, 13 |
| 10 | [] | — | — | Bitti |
Sonuç: 8, 3, 10, 1, 6, 14, 4, 7, 13 — yani seviye seviye:
Seviye 0: 8
Seviye 1: 3, 10
Seviye 2: 1, 6, 14
Seviye 3: 4, 7, 13
Postorder'ın altın kuralı
Postorder’da kök her zaman son elemandır. Preorder’da kök her zaman ilk elemandır. Sınavda “postorder çıktısı verilmiş, kök hangisidir?” diye sorulursa cevap son elemandır.
DFS'te neden stack, BFS'te neden queue?
Stack LIFO olduğu için en son eklenen (en derindeki) düğüm ilk işlenir → derine iner. Queue FIFO olduğu için en önce eklenen (en sığdaki) düğüm ilk işlenir → seviye seviye ilerler. Sadece veri yapısını değiştirerek DFS’i BFS’e çevirebilirsiniz — algoritmanın geri kalanı aynı kalır.
Kendini test et
5, 3, 8, 2, 4, 7, 9 sırasıyla bir BST kurun ve dört dolaşmayı yazın.
Cevabı göster
5
/ \
3 8
/ \ / \
2 4 7 9
Preorder : 5, 3, 2, 4, 8, 7, 9
Inorder : 2, 3, 4, 5, 7, 8, 9 ← sıralı
Postorder : 2, 4, 3, 7, 9, 8, 5
BFS : 5, 3, 8, 2, 4, 7, 9
Hangisi ne zaman kullanılır?
| Dolaşma | Kullanım alanı |
|---|---|
| Preorder | Ağacı kopyalama / serialize etme (kök önce geldiği için aynı ağaç yeniden kurulabilir), dizin ağacını yazdırma |
| Inorder | BST’yi sıralı okuma, ağacın BST olup olmadığını doğrulama |
| Postorder | Ağacı silme / bellek boşaltma, alt sonuçlardan üstü hesaplama (klasör boyutu toplama), postfix ifade üretme |
| Level-order (BFS) | Seviye seviye işleme, ağacın derinliğini/genişliğini bulma, en kısa yol |
Karmaşıklık: Hepsi zamanda O(n) — her düğüme bir kez uğranır. Bellekte DFS O(h) (h = yükseklik, recursion stack; en kötü O(n)), BFS O(w) (w = en geniş seviyedeki düğüm sayısı; en kötü O(n)).
Ağaçta DFS/BFS ile grafta DFS/BFS farkı
Ağaçta döngü (cycle) yoktur, her düğüme tek bir yoldan gidilir; bu yüzden visited listesi tutmaya gerek yoktur. Grafta ise sonsuz döngüye girmemek için visited seti şarttır.
İfade ağacı (Expression Tree)
(3 + 5) * 2 ifadesinin ağacı:
*
/ \
+ 2
/ \
3 5
- Preorder → prefix:
* + 3 5 2 - Inorder → infix:
3 + 5 * 2 - Postorder → postfix (RPN):
3 5 + 2 *
Python referans kodu
Ağaç kurma, dört dolaşma, arama ve yükseklik — tam kod
from collections import deque
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
# --- Verilen sayıları BST'ye çevirme ---
def insert(root, value):
if root is None: # boş yer bulundu → yeni düğüm
return Node(value)
if value < root.value:
root.left = insert(root.left, value)
elif value > root.value:
root.right = insert(root.right, value)
return root # eşit değer → yok say
def build_bst(numbers):
root = None
for n in numbers:
root = insert(root, n)
return root
# --- DFS: üç dolaşma (recursive) ---
def preorder(node, out): # Kök - Sol - Sağ
if node is None: return
out.append(node.value)
preorder(node.left, out)
preorder(node.right, out)
def inorder(node, out): # Sol - Kök - Sağ (BST'de sıralı çıkar)
if node is None: return
inorder(node.left, out)
out.append(node.value)
inorder(node.right, out)
def postorder(node, out): # Sol - Sağ - Kök
if node is None: return
postorder(node.left, out)
postorder(node.right, out)
out.append(node.value)
# --- DFS: stack ile (recursion'sız, preorder sırası) ---
def dfs_iterative(root):
if root is None: return []
out, stack = [], [root]
while stack:
node = stack.pop()
out.append(node.value)
if node.right: stack.append(node.right) # önce sağ eklenir ki
if node.left: stack.append(node.left) # sol önce işlensin
return out
# --- Inorder'ın iteratif hali (klasik mülakat sorusu) ---
def inorder_iterative(root):
out, stack, cur = [], [], root
while stack or cur:
while cur: # sola sonuna kadar in, yolu stack'e yaz
stack.append(cur)
cur = cur.left
cur = stack.pop() # en soldaki düğüm
out.append(cur.value) # yaz
cur = cur.right # sağa geç
return out
# --- BFS: queue ile (level-order) ---
def level_order(root):
if root is None: return []
out, q = [], deque([root])
while q:
node = q.popleft()
out.append(node.value)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
return out
# --- BST'de arama: O(log n) (dengeliyse) ---
def search(root, target):
while root:
if target == root.value: return True
root = root.left if target < root.value else root.right
return False
# --- Ağacın yüksekliği ---
def height(node):
if node is None: return -1 # yaprak yüksekliği 0 olsun diye -1
return 1 + max(height(node.left), height(node.right))
# --- Kullanım ---
sayilar = [8, 3, 10, 1, 6, 14, 4, 7, 13]
root = build_bst(sayilar)
out = []; preorder(root, out); print("Preorder :", out) # [8,3,1,6,4,7,10,14,13]
out = []; inorder(root, out); print("Inorder :", out) # [1,3,4,6,7,8,10,13,14]
out = []; postorder(root, out); print("Postorder:", out) # [1,4,7,6,3,13,14,10,8]
print("BFS :", level_order(root)) # [8,3,10,1,6,14,4,7,13]
print("Yükseklik:", height(root)) # 3
print("6 var mı?:", search(root, 6)) # True
Bonus soru
“Preorder ve Inorder verildi, ağacı çiz.” → Preorder’ın ilk elemanı köktür; o kökü Inorder’da bul, solunda kalanlar sol alt ağaç, sağında kalanlar sağ alt ağaçtır. Aynı işlemi parçalara özyinelemeli uygula. (Preorder + Postorder ikilisi tek başına yeterli değildir — ikisi de kökün yerini belirler ama sol/sağ ayrımını yapmaz.)
Heap
Öncelik kuyruğu (Priority Queue) oluşturmak için kullanılan ağaç tabanlı yapıdır.
- Min Heap: En küçük eleman root’tadır.
- Max Heap: En büyük eleman root’tadır.
- Ekleme/çıkarma: O(log n); root’a bakma: O(1). Heap Sort algoritmasının temelidir.
Graph (Graf)
Düğümler (vertex) ve kenarlardan (edge) oluşur; yönlü (directed) veya yönsüz (undirected) olabilir. Sosyal ağlar ve harita/rota uygulamalarında kullanılır.
- BFS: Genişlik öncelikli; kuyruk kullanır. Ağırlıksız grafta en kısa yolu bulur.
- DFS: Derinlik öncelikli; stack veya recursion kullanır. Döngü tespiti, topolojik sıralama, bağlı bileşen bulmada kullanılır.
- Her ikisi de O(V + E) (V = düğüm, E = kenar sayısı).
- Ağaçtan tek farkı: Grafta döngü olabileceği için
visitedseti tutulmak zorundadır; yoksa sonsuz döngüye girilir.
# Graf üzerinde BFS ve DFS (komşuluk listesi: {"A": ["B", "C"], ...})
from collections import deque
def bfs(graph, start):
visited, order, q = {start}, [], deque([start])
while q:
node = q.popleft()
order.append(node)
for komsu in graph[node]:
if komsu not in visited:
visited.add(komsu)
q.append(komsu)
return order
def dfs(graph, node, visited=None, order=None):
if visited is None: visited, order = set(), []
visited.add(node)
order.append(node)
for komsu in graph[node]:
if komsu not in visited:
dfs(graph, komsu, visited, order)
return order
Bölüm 3 — Algoritmalar
Algoritma Karmaşıklığı
- Time Complexity: Girdi boyutu (n) arttıkça çalışma süresinin nasıl değiştiğini ifade eder. Örn: \(O(n^2)\) → girdi 2 katına çıkarsa süre yaklaşık 4 katına çıkar.
- Space Complexity: Girdi büyüdükçe ihtiyaç duyulan ek bellek miktarının değişimidir.
Big-O karşılaştırması (iyiden kötüye)
O(1) → sabit (hash table erişimi)
O(log n) → logaritmik (binary search)
O(n) → doğrusal (linear search)
O(n log n) → linearitmik (merge sort, quick sort ortalama)
O(n²) → karesel (bubble, selection, insertion sort)
O(2ⁿ) → üstel (naif fibonacci recursion)
O(n!) → faktöriyel (brute-force gezgin satıcı)
Algoritma Gösterim Şekilleri
- Pseudocode (Sözde Kod): Adımları programlama dilinden bağımsız, konuşma diline yakın ifade etme.
- Flowchart (Akış Şeması): Adımları geometrik şekiller ve oklarla görsel ifade etme. Elips = başla/bitir, dikdörtgen = işlem, baklava dilimi = karar, paralelkenar = girdi/çıktı.
Arama Algoritmaları
- Linear Search: Elemanları sırayla tek tek kontrol eder. O(n). Sırasız listelerde de çalışır.
- Binary Search: Yalnızca sıralı listelerde çalışır. Ortaya bakar; aranan küçükse sola, büyükse sağa devam eder. O(log n).
Neden Binary Search O(log n)?
Her adımda problem boyutu yarıya iner. n elemanı 1’e indirmek için yaklaşık \(\log_2 n\) adım gerekir. Somut örnek: 1024 eleman → en fazla 10 karşılaştırma. Milyon eleman → 20 karşılaştırma.
Sıralama Algoritmaları
| Algoritma | En İyi | Ortalama | En Kötü | Ek Bellek | Not |
|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | En basit, verimsiz |
| Selection Sort | O(n²) | O(n²) | O(n²) | O(1) | Her turda min bulur |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Neredeyse sıralı listede hızlı |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Divide & conquer, kararlı (stable) |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | Pivot tabanlı, pratikte en hızlı |
- Bubble Sort: Komşu elemanları ikili karşılaştırır, yanlış sıradaysa yer değiştirir; liste sıralanana kadar tekrar eder.
- Selection Sort: Her iterasyonda kalanlar arasından en küçüğü bulup doğru konuma koyar.
- Insertion Sort: Elemanları tek tek alıp sıralı bölümde doğru yere yerleştirir.
- Merge Sort: Listeyi ikiye böler, parçaları sıralar, birleştirir.
- Quick Sort: Pivot seçer; küçükler sola, büyükler sağa. Alt parçalara aynı işlemi uygular. En kötü durumu (O(n²)) pivot hep en küçük/en büyük seçilirse oluşur.
flowchart TD
A["[38, 27, 43, 3]"] --> B["[38, 27]"]
A --> C["[43, 3]"]
B --> D["[38]"]
B --> E["[27]"]
C --> F["[43]"]
C --> G["[3]"]
D --> H["[27, 38]"]
E --> H
F --> I["[3, 43]"]
G --> I
H --> J["[3, 27, 38, 43]"]
I --> JMerge Sort: böl → sırala → birleştir.
Recursion (Özyineleme)
Fonksiyonun kendini çağırmasıdır. Mutlaka bir base case (temel durum) olmalıdır; yoksa sonsuz döngü oluşur ve stack overflow ile biter. Klasik örnekler: faktöriyel, Fibonacci, ağaç dolaşmaları.
Bölüm 4 — Sayı Sistemleri, Bit İşlemleri ve Mantık Kapıları
Sayı Sistemleri
| Sistem | Taban | Rakamlar | Örnek |
|---|---|---|---|
| İkilik (Binary) | 2 | 0, 1 | 1011₂ |
| Sekizlik (Octal) | 8 | 0–7 | 27₈ |
| Onluk (Decimal) | 10 | 0–9 | 23₁₀ |
| Onaltılık (Hex) | 16 | 0–9, A–F | 2F₁₆ |
Her bit, sağdan sola 2⁰, 2¹, 2², … ağırlığıyla çarpılıp toplanır:
1011₂ = 1·8 + 0·4 + 1·2 + 1·1 = 11₁₀
110101₂ = 32 + 16 + 4 + 1 = 53₁₀
Pratik ipucu: sadece 1 olan basamakların ağırlıklarını toplayın, sıfırları hiç yazmayın.
Sayı sürekli 2’ye bölünür, kalanlar not edilir; sonuç kalanların tersten okunmasıdır:
25 / 2 = 12 kalan 1
12 / 2 = 6 kalan 0
6 / 2 = 3 kalan 0
3 / 2 = 1 kalan 1
1 / 2 = 0 kalan 1
Tersten oku → 25₁₀ = 11001₂
Her hex rakamı tam olarak 4 bite karşılık gelir. Binary’yi sağdan 4’erli grupla, her grubu hex’e çevir (tersi de aynı):
10111100₂ → 1011 | 1100 → B | C → BC₁₆
2F₁₆ → 0010 | 1111 → 00101111₂
Onluk → onaltılık için: sürekli 16’ya bölme (kalanlar tersten) veya önce ikiliğe çevirip 4’erli gruplama.
Two’s Complement (İkiye Tümleyen) sık sorulur
Bilgisayarlar negatif tamsayıları two’s complement ile tutar.
Hesaplama: Tüm bitleri ters çevir (one’s complement) → 1 ekle.
8 bitte -5:
5 = 00000101
ters = 11111010 (one's complement)
+1 = 11111011 → -5
- En soldaki bit (MSB) işaret göstergesidir: 1 ise negatif.
- n bitin aralığı: \(-2^{n-1} \ldots 2^{n-1}-1\) — 8 bit için −128 … +127. Negatif taraf bir fazladır.
- Geri çevirmek için aynı işlem tekrar uygulanır (ters çevir + 1).
- Doğrulama:
5 + (-5) = 00000101 + 11111011 = 1 00000000→ taşan bit atılır, sonuç 0 ✓
Neden two's complement kullanılır?
Toplama ve çıkarma aynı donanım devresiyle yapılır (çıkarma = negatifin toplanması) ve tek bir sıfır gösterimi vardır. Alternatif olan “işaret biti + büyüklük” gösteriminde hem +0 hem -0 olurdu, hem de ayrı bir çıkarma devresi gerekirdi.
Bitwise (Bit Düzeyi) Operatörler
12 = 1100, 10 = 1010 üzerinden:
| Operatör | Adı | Kural | Örnek |
|---|---|---|---|
& | AND | İkisi de 1 ise 1 | 12 & 10 = 1000 = 8 |
| | OR | En az biri 1 ise 1 | 12 | 10 = 1110 = 14 |
^ | XOR | Farklıysa 1 | 12 ^ 10 = 0110 = 6 |
~ | NOT | Bitleri tersler | ~12 = −13 (two’s complement: ~n = -n-1) |
<< | Sola kaydırma | Her kaydırma ×2 | 1 << 3 = 8, 3 << 2 = 12 |
>> | Sağa kaydırma | Her kaydırma ÷2 (taban) | 12 >> 2 = 3 |
Klasik bit soruları
Altı klasik bit numarası — elle yazabilmeli
# 1) Tek mi çift mi? — son bit 1 ise tektir
def tek_mi(n):
return n & 1 == 1
# 2) 2'nin kuvveti mi? — 2^k'nin binary'sinde tek bir 1 vardır (1000...),
# n-1 o biti söndürüp sağını 1 yapar (0111...) → AND'leri 0 olur
def ikinin_kuvveti(n):
return n > 0 and (n & (n - 1)) == 0
# 8 = 1000, 7 = 0111 → 8 & 7 = 0 ✓ | 6 = 110, 5 = 101 → 6 & 5 = 100 ≠ 0 ✗
# 3) XOR ile swap — geçici değişken kullanmadan
a, b = 5, 9
a = a ^ b
b = a ^ b # (a^b)^b = a
a = a ^ b # (a^b)^a = b
# 4) i'inci biti oku / set et / temizle / tersle (i sağdan, 0'dan başlar)
oku = (n >> i) & 1
setle = n | (1 << i)
temizle = n & ~(1 << i)
tersle = n ^ (1 << i)
# 5) 1 bitlerini sayma (Brian Kernighan): her adım en sağdaki 1'i söndürür
def bit_say(n):
sayac = 0
while n:
n &= n - 1
sayac += 1
return sayac
# 6) Herkes 2 kez, biri 1 kez varsa tekil elemanı bul: hepsini XOR'la
# (x ^ x = 0 ve x ^ 0 = x olduğundan çiftler birbirini yok eder)
def tekil(dizi):
sonuc = 0
for x in dizi:
sonuc ^= x
return sonuc
Mantık Kapıları (Logic Gates)
Tek girişli NOT (tersleyici): 0→1, 1→0. İki girişli kapıların tümü tek tabloda:
| A | B | AND | OR | XOR | NAND | NOR | XNOR |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
| 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
| 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 |
- NAND = NOT(AND), NOR = NOT(OR), XNOR = NOT(XOR) — “eşitse 1”.
- XOR: girişler farklıysa 1. Parity kontrolünde ve toplayıcı devrelerde kullanılır.
- Half adder (yarım toplayıcı):
Sum = A ⊕ B,Carry = A · B— “bit toplama devresi nasıl kurulur?” sorusunun cevabı.
Neden NAND ve NOR 'evrensel kapı'dır?
Yalnızca NAND’lerle (veya yalnızca NOR’larla) NOT, AND, OR — dolayısıyla her devre — kurulabilir. En basit örnek: NOT A = A NAND A. Üretimde tek kapı tipiyle çalışmak basitlik ve maliyet avantajı sağlar.
Multiplexer (MUX) ve Demultiplexer (DEMUX) devre çizimi sorulur
MUX (çoklayıcı): Birden fazla giriş arasından birini seçip tek bir çıkışa veren devredir — donanımdaki if/else, ya da elektronik bir anahtar. Hangi girişin seçileceğini select (seçme) hatları belirler.
2:1 MUX iki giriş (I₀, I₁), bir seçme hattı (S) ve bir çıkıştan (Y) oluşur. Sadece üç kapıyla kurulur: bir NOT, iki AND, bir OR.
S alt AND'i doğrudan, üst AND'i ise NOT üzerinden besler — bu yüzden her an tam olarak bir AND kapısı açıktır.Devre nasıl okunur? İki AND kapısı birer kapı bekçisi gibi çalışır ve S ile tersi (S̄) birbirinin zıddı olduğu için ikisi asla aynı anda açılamaz:
| S | Üst AND (I₀ · S̄) | Alt AND (I₁ · S) | Y |
|---|---|---|---|
| 0 | S̄ = 1 → açık, I₀ geçer | S = 0 → kapalı, çıkışı 0 | I₀ |
| 1 | S̄ = 0 → kapalı, çıkışı 0 | S = 1 → açık, I₁ geçer | I₁ |
Kapalı AND’in çıkışı her zaman 0 olduğu ve 0 + X = X olduğu için, OR kapısı açık olan tarafın değerini olduğu gibi geçirir. MUX’un çalışma mantığı tam olarak budur.
Doğruluk tablosu:
| S | I₀ | I₁ | Y |
|---|---|---|---|
| 0 | 0 | x | 0 |
| 0 | 1 | x | 1 |
| 1 | x | 0 | 0 |
| 1 | x | 1 | 1 |
(x = don’t care — seçilmeyen girişin değeri çıkışı etkilemez.)
Boyut kuralı ve DEMUX
Ezber: n seçme hattı → 2ⁿ giriş
Bir MUX’un giriş sayısı ile seçme hattı sayısı arasındaki bağıntı:
$$ \text{giriş sayısı} = 2^{\,n} \quad (n = \text{seçme hattı sayısı}) $$| MUX | Giriş | Seçme hattı | Çıkış |
|---|---|---|---|
| 2:1 | 2 | 1 (S) | 1 |
| 4:1 | 4 | 2 (S₁S₀) | 1 |
| 8:1 | 8 | 3 (S₂S₁S₀) | 1 |
| 16:1 | 16 | 4 | 1 |
Sınavda “8 girişli bir MUX için kaç seçme hattı gerekir?” diye sorulursa: \(2^3 = 8\) → 3.
DEMUX (çözücü / demultiplexer) tam tersidir: tek girişi, seçme hatlarının gösterdiği birden fazla çıkıştan birine yönlendirir. Diğer çıkışlar 0 kalır.
flowchart LR
subgraph MUX ["MUX — çok giriş, tek çıkış"]
direction LR
A1[I0] --> M{{"MUX"}}
A2[I1] --> M
A3[I2] --> M
A4[I3] --> M
M --> AY[Y]
AS[S1 S0] -.seçme.-> M
end
subgraph DEMUX ["DEMUX — tek giriş, çok çıkış"]
direction LR
B1[I] --> D{{"DEMUX"}}
D --> BY1[Y0]
D --> BY2[Y1]
D --> BY3[Y2]
D --> BY4[Y3]
BS[S1 S0] -.seçme.-> D
endNerede kullanılır?
ALU: Toplama, çıkarma, AND, OR sonuçlarının hepsi paralel hesaplanır; hangisinin çıkışa verileceğini bir MUX seçer — işlemcideki “komut seçimi” budur.
Veri yolu (bus) paylaşımı: Birden fazla kaynağın tek bir hattı sırayla kullanması.
Bellek adresleme: Adres bitleri, hangi satırın okunacağını seçen bir DEMUX/decoder’ı sürer.
İletişim: Çok sayıda sinyalin tek kanaldan taşınması (multiplexing); karşı uçta DEMUX ile ayrıştırılır. HTTP/2’deki multiplexing kelimesi de aynı fikirden gelir — tek bağlantıda çok istek.
Kablo tasarrufu: n hat yerine \(\log_2 n\) seçme hattı ile aynı iş yapılır.
Sınav sorusu: 4:1 MUX'u 2:1 MUX'larla kurun
Klasik bir “yapı taşından yapı kurma” sorusudur. Üç adet 2:1 MUX yeterlidir:
I0 ─┐
├─ MUX-A ─┐
I1 ─┘ ↑ │
S0 ├─ MUX-C ── Y
I2 ─┐ │ ↑
├─ MUX-B ─┘ S1
I3 ─┘ ↑
S0
- Birinci katman: MUX-A
S0ile I₀/I₁ arasından, MUX-B yineS0ile I₂/I₃ arasından seçer. - İkinci katman: MUX-C,
S1ile bu iki sonuçtan birini seçer.
Yani S1 hangi çifte bakılacağını, S0 o çiftin hangi elemanı olduğunu belirler — ikisi birlikte S1S0 = 00, 01, 10, 11 ile dört girişi adresler. Aynı mantıkla 8:1 MUX, yedi adet 2:1 MUX ile (üç katman) kurulabilir.
Boole Cebri ve De Morgan Kuralları
Temel özdeşlikler: A+0=A, A·1=A, A+A'=1, A·A'=0, A+A=A, A·A=A, (A')'=A, A+A·B=A (absorption).
De Morgan çok sık sorulur
(A · B)' = A' + B' → "AND'in değili = değillerin OR'u"
(A + B)' = A' · B' → "OR'un değili = değillerin AND'i"
Programlamadaki karşılığı — koşul sadeleştirme:
not (a and b) == (not a) or (not b)
not (a or b) == (not a) and (not b)
# örn: not (x > 0 and y > 0) → x <= 0 or y <= 0
Doğruluk Tablosu Oluşturma
n değişken → \(2n\) satır. Satırlar, 0’dan \(2n-1\)’e kadar ikilik sayarak yazılır.
Pratik yazma kuralı: en sağ sütun 0101… diye teker, bir solundaki 0011… diye ikişer, sonraki 00001111… diye dörder değişir; en sol sütunun üst yarısı 0, alt yarısı 1 olur.
Örnek: F = (A · B) + C’ için 3 değişkenli tablo (2³ = 8 satır):
| A | B | C | A·B | C’ | F = A·B + C’ |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 1 | 1 |
| 0 | 0 | 1 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 1 | 1 |
| 1 | 0 | 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 | 1 |
Ara sütunlar (A·B, C') eklemek hem hatayı azaltır hem de “adımları göster” beklentisini karşılar.
Minterm gösterimi: F’nin 1 olduğu satır numaraları. Yukarıdaki tablo için F = Σm(0, 2, 4, 6, 7).
Karnaugh Haritası (K-Map)
Boole ifadesini cebirsel uğraş olmadan görsel olarak sadeleştirme yöntemidir. Doğruluk tablosundaki 1’ler haritaya yerleştirilir, komşu 1’ler gruplanır.
Kritik kural — Gray code sıralaması
Satır/sütun başlıkları 00, 01, 11, 10 sırasıyla yazılır — normal ikilik sayım değil. Böylece komşu hücreler arasında yalnızca tek bit değişir; grup içinde değişen değişken ifadeden elenir. Sadeleştirmenin çalışma sebebi tam olarak budur.
Gruplama kuralları:
- Yalnızca 1’ler gruplanır; grup boyutu 2’nin kuvveti olmalı (1, 2, 4, 8, 16).
- Gruplar dikdörtgen/kare olmalı; çapraz olmaz.
- Harita kenarlardan sarmalanır (wrap-around): en sol–en sağ sütunlar ve en üst–en alt satırlar komşudur; dört köşe tek grup olabilir.
- Mümkün olan en büyük grupları seç; gruplar örtüşebilir; her 1 en az bir grupta olmalı.
- Her grup için grup içinde değişmeyen değişkenlerin çarpımı yazılır (0 kalan → değilli, 1 kalan → düz). Gruplar OR ile birleştirilir.
Isınma (3 değişken): F(A,B,C) = Σm(1, 3, 5, 7) → 1 olan tüm mintermlerde C = 1, A ve B her değeri alıyor → F = C.
Örnek soru (4 değişken): F(A,B,C,D) = Σm(0, 2, 5, 7, 8, 10, 13, 15) ifadesini K-map ile sadeleştirin.
Minterm numarası = 8A + 4B + 2C + 1D. Harita (satır AB, sütun CD, Gray code sırasıyla):
| AB \ CD | 00 | 01 | 11 | 10 |
|---|---|---|---|---|
| 00 | 1 (m0) | 0 | 0 | 1 (m2) |
| 01 | 0 | 1 (m5) | 1 (m7) | 0 |
| 11 | 0 | 1 (m13) | 1 (m15) | 0 |
| 10 | 1 (m8) | 0 | 0 | 1 (m10) |
Çözümü göster
- Grup 1 — dört köşe (m0, m2, m8, m10; wrap-around sayesinde tek bir 4’lük grup): hepsinde B = 0, D = 0; A ve C değişiyor → elenir → terim: B’D’
- Grup 2 — ortadaki 2×2 kare (m5, m7, m13, m15): hepsinde B = 1, D = 1; A ve C değişiyor → terim: BD
Sonuç: F = BD + B'D' — yani B XNOR D (B ile D eşitse 1).
Sadeleştirme olmasaydı 8 mintermlik, her biri 4 değişkenli bir ifade yazılacaktı; K-map bunu iki terime indirdi.
Sık teori sorusu
“K-map’te başlıklar neden 00, 01, 11, 10 sırasıyla yazılır?” — Gray code’da ardışık hücreler arasında tek bit değişir; komşu 1’ler gruplandığında değişen o değişken elenebilir. Normal sıralamada (00, 01, 10, 11) komşu hücreler arasında iki bit birden değişebilir ve gruplama mantığı bozulur.
Bölüm 5 — Otomata Teorisi ve Chomsky Hiyerarşisi
Bilgisayar biliminin teorik temelidir. Soru genelde üç eksende gelir: (1) Chomsky hiyerarşisinin katmanları, (2) her katmana karşılık gelen makine, (3) “şu dil hangi sınıftandır?” örnekleri.
Temel Kavramlar
| Terim | Tanım | Örnek |
|---|---|---|
| Alfabe (Σ) | Sonlu sembol kümesi | Σ = {a, b} veya {0, 1} |
| String / Kelime (w) | Alfabedeki sembollerin sonlu dizisi | aabba |
| ε (epsilon) | Boş string (uzunluğu 0) | — |
| Σ* | Alfabeden üretilebilen tüm stringler (Kleene closure) | {ε, a, b, aa, ab, …} |
| Dil (L) | Σ*‘ın bir alt kümesi — seçilmiş string’ler kümesi | L = {aⁿbⁿ | n ≥ 1} |
| Gramer (G) | Dili üreten kurallar takımı | S → aSb | ab |
| Otomat | Bir string’i okuyup kabul/ret kararı veren soyut makine | DFA, PDA, TM |
Gramerin dört bileşeni: G = (V, T, P, S)
- V (Variables / Non-terminal): Büyük harfler — S, A, B (henüz açılacak semboller)
- T (Terminals): Küçük harfler — a, b, 0, 1 (nihai semboller)
- P (Production rules): Üretim kuralları —
S → aSb - S (Start symbol): Başlangıç sembolü
Türetme (derivation) örneği: S → aSb | ab grameriyle aaabbb üretimi:
S ⇒ aSb ⇒ aaSbb ⇒ aaabbb ✓
Chomsky Hiyerarşisi (1956) en çok sorulan tablo
Noam Chomsky’nin dilleri üretici güçlerine göre dört seviyeye ayırmasıdır. İç içe geçmiştir: Tip 3 ⊂ Tip 2 ⊂ Tip 1 ⊂ Tip 0. Yani her düzenli dil aynı zamanda bağlamdan bağımsızdır; tersi doğru değildir.
| Tip | Dil Sınıfı | Gramer | Tanıyan Makine | Bellek |
|---|---|---|---|---|
| Tip 3 | Regular (Düzenli) | Regular Grammar | Finite Automaton (FA/DFA/NFA) | Bellek yok, sadece durum |
| Tip 2 | Context-Free (Bağlamdan Bağımsız) | Context-Free Grammar (CFG) | Pushdown Automaton (PDA) | 1 stack |
| Tip 1 | Context-Sensitive (Bağlama Duyarlı) | Context-Sensitive Grammar | Linear Bounded Automaton (LBA) | Sınırlı bant (girdi uzunluğuyla orantılı) |
| Tip 0 | Recursively Enumerable | Unrestricted Grammar | Turing Machine (TM) | Sınırsız bant |
flowchart TD
A["Tip 0 — Recursively Enumerable<br/>Turing Machine"] --> B["Tip 1 — Context-Sensitive<br/>Linear Bounded Automaton"]
B --> C["Tip 2 — Context-Free<br/>Pushdown Automaton"]
C --> D["Tip 3 — Regular<br/>Finite Automaton"]İçteki her küme dıştakinin alt kümesidir: Tip 3 en kısıtlı, Tip 0 en güçlü.
Kural biçimleri (α → β)
| Tip | Kural biçimi | Örnek | Açıklama |
|---|---|---|---|
| Tip 3 | A → aB veya A → a | S → aS | b | Sol taraf tek non-terminal; sağ tarafta en fazla bir non-terminal ve o da hep aynı uçta |
| Tip 2 | A → γ | S → aSb | ε | Sol taraf tek non-terminal; sağ taraf serbest |
| Tip 1 | αAβ → αγβ | aSb → aaSbb | Sol taraf birden fazla sembol olabilir; |sol| ≤ |sağ| (kısalma yok) |
| Tip 0 | α → β | aSb → c | Kısıt yok; kısalma serbest |
“Bu dil hangi tiptendir?”
| Dil | Tip | Neden? |
|---|---|---|
a*b* (önce a’lar sonra b’ler, sayı serbest) | Regular (3) | Saymaya gerek yok, sadece “hangi bölümdeyim” bilgisi yeter |
Çift sayıda a içeren stringler | Regular (3) | 2 durum yeter (tek/çift) — sonlu bellek |
| aⁿbⁿ (a sayısı = b sayısı) | Context-Free (2) | Saymak gerekir → stack şart. FA yapamaz |
Dengeli parantez ((())) | Context-Free (2) | Aç-kapa eşleşmesi stack ile yapılır |
| Palindromlar | Context-Free (2) | İlk yarıyı stack’e at, ikinci yarıda karşılaştır |
| aⁿbⁿcⁿ (üç sembol de eşit) | Context-Sensitive (1) | Tek stack yetmez; iki bağımsız sayım gerekir |
ww (bir string’in kendisiyle tekrarı) | Context-Sensitive (1) | Kopyalama, PDA’nın gücünü aşar |
| Halting problem dili | Recursively Enumerable (0) | Yalnızca TM ile “kabul” edilir; karar verilemez |
Ezberlenmesi gereken kısa cevap
aⁿbⁿ neden regular değildir? Çünkü sonlu otomatın belleği yoktur; kaç tane a gördüğünü hatırlayamaz. n sınırsız olduğu için sonlu sayıda durumla sayılamaz. Bu, Pumping Lemma ile ispatlanır.
Sonlu Otomatlar (Finite Automata) — Tip 3
M = (Q, Σ, δ, q₀, F) beş bileşenden oluşur:
- Q: Durumlar kümesi
- Σ: Giriş alfabesi
- δ: Geçiş fonksiyonu (transition function)
- q₀: Başlangıç durumu
- F: Kabul (final) durumları kümesi
DFA vs NFA çok sık sorulur
| DFA (Deterministic) | NFA (Non-deterministic) | |
|---|---|---|
| Geçiş | Her durum-sembol çifti için tam 1 geçiş | 0, 1 veya birden fazla geçiş olabilir |
| δ tipi | δ: Q × Σ → Q | δ: Q × (Σ ∪ {ε}) → 2^Q |
| ε-geçişi | Yok | Var |
| Güç | — | Eşit güçtedir! Her NFA bir DFA’ya dönüştürülebilir (subset construction) |
| Durum sayısı | Daha fazla olabilir (en kötü 2ⁿ) | Daha az / kompakt |
| Uygulama | Doğrudan kodlanır, hızlı | Tasarımı kolay |
Tuzak soru
“NFA, DFA’dan daha güçlü müdür?” → Hayır. İkisi de tam olarak düzenli dilleri tanır. NFA sadece daha kısa yazılır; her NFA determinize edilebilir.
Örnek DFA — “çift sayıda a içeren stringler”:
stateDiagram-v2
direction LR
[*] --> Cift
Cift --> Tek : a
Tek --> Cift : a
Cift --> Cift : b
Tek --> Tek : b
Cift --> [*]Çift = kabul durumu. abba → Çift→Tek→Tek→Tek→Çift = kabul. aab → Çift→Tek→Çift→Çift = kabul. ab → Tek = ret.
Regular Expression ↔ Regular Language: Düzenli ifadeler (regex) ile sonlu otomatlar denk güçtedir (Kleene Teoremi). a*b+, (a|b)*abb gibi ifadeler birer DFA’ya çevrilebilir.
Neden regex ile HTML/parantez parse edilemez?
HTML iç içe (nested) yapıdadır, yani context-free‘dir; regex ise yalnızca regular dilleri tanır. İç içe açılış-kapanışları saymak için stack gerekir, saf teorik anlamda regex motorunda stack yoktur.
Pushdown Automaton (PDA) — Tip 2
Sonlu otomat + bir stack. aⁿbⁿ için mantık:
- Her
agördüğünde stack’e bir sembol push et. - Her
bgördüğünde stack’ten bir sembol pop et. - String bitince stack boşsa kabul, değilse ret.
DPDA vs NPDA: Sonlu otomatların aksine burada NPDA, DPDA’dan güçlüdür. Örneğin tüm palindromlar dili NPDA ile tanınır, DPDA ile tanınmaz.
Pratikteki karşılığı: Programlama dillerinin sözdizimi (syntax) context-free’dir; derleyicilerdeki parser aşaması bir PDA’dır. Ama “değişken kullanılmadan önce tanımlanmış mı” gibi kurallar context-sensitive’dir; bu yüzden derleyiciler ayrı bir semantik analiz aşaması kullanır.
Turing Makinesi (TM) — Tip 0
Sonsuz bir bant üzerinde okuma/yazma yapabilen, başlığı sağa-sola hareket ettirebilen soyut makinedir. Hesaplanabilirliğin sınırını tanımlar.
- Church-Turing Tezi: “Algoritmayla hesaplanabilen her şey bir Turing makinesiyle hesaplanabilir.” Modern bilgisayarlar (sonsuz bellek varsayımıyla) Turing-complete’tir.
- Decidable (Karar verilebilir): TM her girdide durur ve evet/hayır der → Recursive diller.
- Recursively Enumerable: TM “evet” olan girdilerde durur, “hayır” olanlarda sonsuza kadar çalışabilir.
- Halting Problem (Durma Problemi): “Verilen bir programın belirli bir girdide durup durmayacağını” belirleyen genel bir algoritma yoktur. Turing tarafından 1936’da ispatlanmıştır — bilgisayar biliminin en temel imkânsızlık sonucudur.
Derleyici ile İlişkisi
| Derleyici aşaması | Kullandığı teori | Makine |
|---|---|---|
| Lexical Analysis (token’lara ayırma) | Regular Language / Regex | Finite Automaton |
| Syntax Analysis (parse tree kurma) | Context-Free Grammar | Pushdown Automaton |
| Semantic Analysis (tip kontrolü, scope) | Context-Sensitive | Attribute grammar / symbol table |
Sınavda söylenecek özet cümle
“Chomsky hiyerarşisi dilleri üretici güçlerine göre dörde ayırır: Regular (sonlu otomat), Context-Free (yığıtlı otomat), Context-Sensitive (lineer sınırlı otomat) ve Recursively Enumerable (Turing makinesi). Her seviye bir öncekini kapsar ve daha fazla bellek gücü gerektirir.”
Bölüm 6 — Programlama Paradigmaları ve Tasarım
Nesne Yönelimli Programlama (OOP)
Programı, veri ve o veri üzerinde işlem yapan metodları içeren nesneler etrafında organize eder. Dört temel prensip:
- Encapsulation (Kapsülleme): Veri ve metodları tek birimde (sınıf) birleştirip veriyi dış müdahaleden korumak.
- Inheritance (Kalıtım): Bir sınıfın özellik ve metodlarını başka sınıfa miras bırakması; kod tekrarını önler.
- Polymorphism (Çok Biçimlilik): Farklı nesnelerin aynı metod çağrısına farklı şekillerde cevap verebilmesi.
- Abstraction (Soyutlama): İç detayları gizleyip yalnızca gerekli özellikleri göstermek.
SOLID Prensipleri
S — Single Responsibility
Her sınıfın tek bir sorumluluğu, yani değişmek için tek bir sebebi olmalı.
O — Open/Closed
Genişlemeye açık, değişime kapalı olmalı. Yeni davranış eklerken mevcut kodu değiştirmemelisin.
L — Liskov Substitution
Türetilmiş sınıflar, ana sınıfın yerine sorunsuz geçebilmeli.
I — Interface Segregation
Sınıf, kullanmadığı metodları içeren bir arayüzü uygulamaya zorlanmamalı.
D — Dependency Inversion
Üst ve alt seviye modüller somut sınıflara değil, soyutlamalara bağlı olmalı.
Clean Code Prensipleri
- DRY — Don’t Repeat Yourself: Kod tekrarından kaçın.
- KISS — Keep It Simple, Stupid: Basit tut.
- YAGNI — You Aren’t Gonna Need It: İhtiyaç olmayan özelliği önceden yazma.
- Separation of Concerns: Farklı sorumlulukları farklı birimlere ayır.
Dependency Injection (Bağımlılık Enjeksiyonu)
Sınıfın ihtiyaç duyduğu bağımlılıkları kendi içinde oluşturmak yerine dışarıdan almasıdır.
- UserService → new MySQLDatabase() // sıkı bağlı, test edilemez
+ UserService → Database (interface) // dışarıdan verilir, mock'lanabilir
Böylece implementasyon değiştirilebilir ve test (mock) kolaylaşır.
Coupling ve Cohesion
- Coupling (Bağlılık): Modüllerin birbirine ne kadar bağımlı olduğu. Düşük olmalı.
- Cohesion (Uyum): Bir modül içindeki sorumlulukların ne kadar ilişkili olduğu. Yüksek olmalı.
İdeal: High Cohesion + Low Coupling.
Fonksiyonel Programlama
Programlamayı matematiksel fonksiyonların değerlendirilmesi olarak görür. Durum (state) ve değişen veriden (mutable data) kaçınır.
Pure function: Aynı girdi için her zaman aynı çıktıyı üreten, yan etkisiz fonksiyon. Kodu tahmin edilebilir ve test edilebilir kılar.
Interface vs Abstract Class sık sorulur
Interface
Sadece metod imzaları içerir — bir sözleşmedir. Bir sınıf birden fazla interface uygulayabilir.
“Ne yapabildiğini” tanımlar.
Abstract Class
Hem soyut hem somut (gövdeli) metod içerebilir, alan (field) barındırabilir. Tek kalıtım vardır.
“Ne olduğunu” ve ortak davranışı tanımlar.
Composition vs Inheritance
- Inheritance: “is-a” ilişkisi (Kedi bir Hayvandır). Sıkı bağlılık yaratabilir.
- Composition: “has-a” ilişkisi (Araba bir Motora sahiptir). Daha esnektir.
Genel kabul: “composition over inheritance” — kalıtım zincirleri büyüdükçe kırılganlaşır.
Tasarım Desenleri (Design Patterns)
| Desen | Ne yapar | Tipik yer |
|---|---|---|
| Singleton | Sınıftan yalnızca tek instance oluşmasını garanti eder | Veritabanı bağlantı yöneticisi, config |
| Factory | Nesne oluşturma mantığını soyutlar; hangi sınıfın üretileceğine çalışma zamanında karar verilir | Ödeme sağlayıcı seçimi |
| Observer | Bir nesnedeki değişikliğin abonelerine otomatik bildirilmesi | Bildirim / event sistemleri |
| Strategy | Bir algoritma ailesini kapsüller, çalışma zamanında değiştirilebilir kılar | Kargo ücreti hesaplama |
| Adapter | Uyumsuz iki interface’in birlikte çalışmasını sağlar | Fiş adaptörü benzetmesi; eski API’yi yeniye sarma |
MVC (Model-View-Controller)
- Model: Veri ve iş mantığı.
- View: Kullanıcı arayüzü.
- Controller: İstekleri alıp Model ile View arasında koordinasyonu sağlar.
Bölüm 7 — Veritabanı ve SQL
SQL Komut Türleri
| Tür | Açılımı | Komutlar |
|---|---|---|
| DDL | Data Definition Language | CREATE, ALTER, DROP, TRUNCATE — yapıyı tanımlar |
| DML | Data Manipulation Language | SELECT, INSERT, UPDATE, DELETE — veri üzerinde işlem |
| DCL | Data Control Language | GRANT, REVOKE — yetkilendirme |
| TCL | Transaction Control Language | COMMIT, ROLLBACK, SAVEPOINT |
Temel Sorgular
-- Filtreleme
SELECT * FROM users WHERE age > 18;
-- Sıralama ve limit
SELECT name, salary FROM employees ORDER BY salary DESC LIMIT 5;
-- Gruplama: GROUP BY gruplar, HAVING grupları filtreler
SELECT department, COUNT(*)
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
WHERE vs HAVING
WHERE satırları gruplamadan önce, HAVING grupları oluştuktan sonra filtreler. Bu yüzden aggregate fonksiyonlar (COUNT, SUM…) yalnızca HAVING’de kullanılabilir — WHERE çalıştığı anda henüz grup yoktur.
DELETE vs TRUNCATE vs DROP sık sorulur
| DELETE | TRUNCATE | DROP | |
|---|---|---|---|
| Ne siler | Koşula uyan satırları | Tüm satırları | Tabloyu ve yapısını |
WHERE alır mı | Evet | Hayır | Hayır |
| Geri alınabilir mi | Evet (rollback) | Genellikle hayır | Hayır |
| Hız | Yavaş (satır satır loglanır) | Hızlı | Hızlı |
| Tür | DML | DDL | DDL |
JOIN Türleri
- INNER JOIN: Her iki tabloda da eşleşen kayıtları getirir.
- LEFT JOIN: Sol tablonun tüm kayıtları + sağdan eşleşenler (eşleşmeyen → NULL).
- RIGHT JOIN: Sağ tablonun tüm kayıtları + soldan eşleşenler.
- FULL OUTER JOIN: Her iki tablonun tüm kayıtları; eşleşmeyen taraflar NULL.
SELECT o.id, c.name
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id;
Primary Key ve Foreign Key
- Primary Key: Her satırı benzersiz tanımlar; NULL olamaz, tekrar edemez.
- Foreign Key: Başka tablonun primary key’ine referans verir; referans bütünlüğünü (referential integrity) sağlar.
Index
Sorguları hızlandıran yapıdır — kitabın arkasındaki dizin gibi. Ancak: ek disk alanı kullanır ve INSERT/UPDATE/DELETE maliyetini artırır, çünkü index de güncellenmek zorundadır.
Neden index sorguyu hızlandırır? Neden her sütuna koymayız?
Hızlandırır, çünkü tam tablo taraması (full scan, O(n)) yerine, index genellikle B-Tree yapısında tutulduğu için aranan kayda \(O(\log n)\) adımda ulaşılır.
Her sütuna koymayız, çünkü her yazma işleminde tüm index’ler güncellenir. Çok index = yavaş yazma + fazla disk kullanımı. Index bir okuma-yazma ödünleşimidir.
Normalizasyon sık sorulur
Veri tekrarını (redundancy) azaltıp bütünlüğü artırmak için tabloların düzenlenmesidir. Tekrar; güncelleme, ekleme ve silme anomalilerine yol açar — normalizasyon bunları önler.
Her hücrede atomik (tek) değer olmalı; tekrarlayan grup/sütun olmamalı, her satır benzersiz olmalı.
İhlal: Telefonlar = "555-111, 555-222" — tek hücrede iki değer.
Çözüm: Her telefon ayrı satır (veya ayrı tablo).
1NF + anahtar olmayan sütunlar birleşik anahtarın tamamına bağlı olmalı (kısmi bağımlılık yok). Yalnızca birleşik anahtarlı tablolarda anlamlıdır.
İhlal: Not(ÖğrenciID, DersID, Not, ÖğrenciAdı) — ÖğrenciAdı yalnızca ÖğrenciID‘ye bağlı, anahtarın tamamına değil.
Çözüm: ÖğrenciAdı Öğrenci tablosuna taşınır.
2NF + anahtar olmayan sütunlar birbirine bağımlı olmamalı (geçişli bağımlılık yok: anahtar → X → Y olmamalı).
İhlal: Öğrenci(ÖğrenciID, BölümID, BölümAdı) — ÖğrenciID → BölümID → BölümAdı.
Çözüm: BölümAdı Bölüm tablosuna taşınır.
3NF’nin daha sıkı hâlidir: her fonksiyonel bağımlılıkta (X → Y) sol taraf X bir süper anahtar olmalıdır. 3NF, aday anahtarın parçasına olan bağımlılıklara izin verebilir; BCNF bunu da yasaklar.
Klasik örnek: Ders(Öğrenci, Ders, Öğretmen) — (Öğrenci, Ders) → Öğretmen ve her öğretmen tek ders veriyorsa Öğretmen → Ders. Öğretmen süper anahtar olmadığı için BCNF ihlalidir.
Çözüm: (Öğrenci, Öğretmen) ve (Öğretmen, Ders) diye ikiye bölünür.
2NF ve 3NF için ezber cümlesi
“Anahtar olmayan her sütun; anahtara, anahtarın tamamına ve yalnızca anahtara bağlı olmalı.” — İngilizcesi: “the key, the whole key, and nothing but the key.”
Denormalizasyon nedir?
Okuma performansı için bilinçli olarak veri tekrarına izin vermektir (JOIN maliyetinden kaçınma). Raporlama ve data warehouse sistemlerinde yaygındır — normalizasyonun “tersi” değil, bilinçli bir ödünleşimdir.
View, Stored Procedure, Trigger
- View: Sorgu sonucunu sanal tablo gibi sunar; veri saklamaz; güvenlik ve basitlik sağlar.
- Stored Procedure: Veritabanında saklanan, önceden derlenmiş SQL bloğu; performans ve güvenlik avantajı.
- Trigger:
INSERT/UPDATE/DELETEgerçekleştiğinde otomatik çalışan kod bloğu.
SQL vs NoSQL çok sık sorulur
| Özellik | SQL (İlişkisel) | NoSQL |
|---|---|---|
| Şema | Sabit, önceden tanımlı | Esnek / şemasız |
| Veri modeli | Tablolar ve ilişkiler | Doküman, key-value, sütun, graf |
| İşlem modeli | ACID | Genellikle BASE |
| Ölçekleme | Dikey (vertical) | Yatay (horizontal) |
| Sorgu | Güçlü, karmaşık JOIN’ler | Basit erişim desenleri |
| Örnek | MySQL, PostgreSQL, Oracle, MSSQL | MongoDB, Redis, Cassandra, Neo4j |
| Uygun senaryo | Bankacılık, ERP, ilişkili veriler | Büyük ölçek, sosyal medya, IoT, cache |
Hangisini seçersin?
Tek doğru cevap yok — gerekçe bekleniyor: güçlü ilişkiler + tutarlılık + karmaşık sorgular → SQL; büyük ölçek + esnek şema + yüksek dağıtıklık → NoSQL. Birçok modern sistem ikisini birlikte kullanır (polyglot persistence).
Büyük Verinin 5 V Kuralı sık sorulur
Big Data’yı tanımlayan beş boyuttur ve aslında “NoSQL neden ortaya çıktı?” sorusunun da cevabıdır: ilişkisel veritabanı bu beş boyutun ilk üçünde zorlanmaya başlayınca yeni modeller doğmuştur.
| V | Türkçe | Ne demek | İlişkisel veritabanını nerede zorlar |
|---|---|---|---|
| Volume | Hacim | Verinin miktarı — TB, PB ölçeğinde | Tek makineye sığmaz; dikey ölçekleme fiziksel duvara toslar → sharding gerekir |
| Velocity | Hız | Verinin üretilme ve işlenme hızı — saniyede milyonlarca olay | Her yazmada index’leri güncelleyen ACID işlemler darboğaz olur → stream/akış işleme gerekir |
| Variety | Çeşitlilik | Verinin türü: yapısal (tablo), yarı yapısal (JSON, XML, log), yapısal olmayan (görsel, video, ses) | Sabit şema bunları taşıyamaz; her yeni alan için ALTER TABLE gerekir |
| Veracity | Doğruluk | Verinin ne kadar güvenilir ve temiz olduğu — eksik alan, çelişkili kayıt, gürültü | Şema doğruluğu zorlar ama anlamsal doğruluğu garanti etmez |
| Value | Değer | Tüm bunların iş anlamında bir karşılığı var mı? | — (teknik değil, iş kararı) |
Ezber ve tarihçe
Orijinal tanım 3 V‘dir — Volume, Velocity, Variety (Doug Laney, 2001). Veracity ve Value sonradan eklenmiştir. Sınavda “5 V” sorulursa üçünü sırayla say, sonra ikisini ekle.
Türkçe ezber: Hacim, Hız, Çeşitlilik, Doğruluk, Değer.
İlk üçü diğer konularla nasıl bağlanıyor?
Volume + Velocity, tek makinenin yetmediği anlamına gelir → yatay ölçekleme zorunlu olur → sistem dağıtık hâle gelir → CAP teoremi devreye girer → ağ bölünmesi kaçınılmaz olduğu için tutarlılıktan ödün verilir → ACID yerine BASE tercih edilir.
Variety ise doğrudan şemasızlığı getirir: aynı koleksiyonda farklı alanlara sahip dokümanlar tutulabilmesi, NoSQL’in doküman modelinin varlık sebebidir.
Yani 5 V, bu bölümdeki SQL/NoSQL, ACID/BASE ve CAP başlıklarını tek bir nedensellik zincirine bağlar — sınavda bu zinciri kurabilmek, tanımları tek tek saymaktan daha değerli.
Sorulursa: 'Bir sistemin Big Data olduğunu nasıl anlarız?'
Tek bir eşik değeri yoktur — “şu kadar TB’den fazlaysa Big Data’dır” diye bir kural aramak yanlış cevaptır. Doğru cevap ölçek değil, yöntem üzerinden verilir:
“Veri; hacmi, üretilme hızı veya çeşitliliği nedeniyle geleneksel araçlarla (tek makine, ilişkisel veritabanı) makul sürede işlenemiyorsa Big Data’dan söz edilir.”
Bu tanım göreceli olduğu için kasıtlıdır: 2005’te Big Data sayılan bir veri kümesi bugün tek bir sunucunun RAM’ine sığabilir.
ACID ve BASE
ACID (genellikle SQL)
Veri bütünlüğü ve güvenilirlik önceliklidir.
- Atomicity — İşlem ya tamamen olur ya hiç olmaz.
- Consistency — İşlem, veritabanını tutarlı bir durumdan diğerine geçirir.
- Isolation — Eşzamanlı işlemler birbirini etkilemez.
- Durability — Başarılı işlem sonrası değişiklikler kalıcıdır.
BASE (genellikle NoSQL)
Erişilebilirlik ve ölçeklenebilirlik önceliklidir.
- Basically Available — Sistem her zaman erişilebilirliği hedefler.
- Soft state — Durum zamanla değişebilir.
- Eventually consistent — Tüm node’lar bir süre sonra aynı veriye ulaşır; anlık tutarlılık zorunlu değildir.
CAP Teoremi
Dağıtık bir sistem aynı anda şu üç garantiden en fazla ikisini sağlayabilir:
- Consistency (Tutarlılık): Tüm node’lar aynı anda aynı veriyi görür.
- Availability (Erişilebilirlik): Her isteğe yanıt alınır.
- Partition Tolerance (Bölünme Toleransı): Ağ kesintilerine rağmen sistem çalışmaya devam eder.
Neden Partition Tolerance'tan vazgeçemeyiz?
Gerçek ağlarda kesinti/bölünme kaçınılmazdır; bir dağıtık sistem ağ bölünmesini “yaşamamayı” seçemez. Bu yüzden pratikte seçim CP (tutarlılık) ile AP (erişilebilirlik) arasındadır. Örnek: banka → CP, sosyal medya akışı → AP.
Vektör Veritabanı (Vector Database)
Metin, resim, ses gibi verileri matematiksel vektörler (embedding) olarak depolayan ve vektörler arasında anlamsal benzerlik araması yapmak için optimize edilmiş veritabanıdır. Benzer görsel bulma, anlamsal metin arama ve RAG sistemlerinde kullanılır.
Bölüm 8 — İşletim Sistemleri
Process ve Thread
- Process: Çalışan bir programın bağımsız yürütme ortamıdır; kendi bellek/adres alanı vardır.
- Thread: Process içinde çalışan en küçük yürütme birimidir; bir process birden fazla thread içerebilir.
| Process | Thread |
|---|---|
| Daha ağırdır | Daha hafiftir |
| Ayrı adres alanı vardır | Aynı process belleğini paylaşır |
| Context switch maliyetlidir | Context switch daha ucuzdur |
| Birbirinden izoledir | Kaynakları paylaşır |
Neden thread oluşturmak process oluşturmaktan ucuzdur?
Yeni process için ayrı adres alanı, sayfa tabloları ve kaynaklar kopyalanır/oluşturulur. Thread ise mevcut process’in belleğini paylaşır; yalnızca kendi stack’i ve register seti oluşturulur.
Concurrency vs Parallelism
- Concurrency (Eşzamanlılık): Birden fazla işin ilerlemesinin yönetilmesi — tek çekirdekte sırayla dönüşümlü de olabilir.
- Parallelism (Paralellik): İşlerin gerçekten aynı anda farklı CPU çekirdeklerinde çalışması.
Deadlock (Kilitlenme)
İki veya daha fazla process’in, birbirinin tuttuğu kaynağı beklemesi ve hiçbirinin ilerleyememesidir.
Dört klasik koşul — hepsi aynı anda sağlanmalı:
- Mutual Exclusion: Kaynak aynı anda tek process tarafından kullanılabilir.
- Hold and Wait: Process kaynak tutarken başka kaynak bekler.
- No Preemption: Kaynak zorla geri alınamaz.
- Circular Wait: Process’ler döngüsel olarak birbirini bekler.
flowchart LR
P1[Process 1] -- tutuyor --> R1[(Kaynak A)]
P2[Process 2] -- tutuyor --> R2[(Kaynak B)]
P1 -- bekliyor --> R2
P2 -- bekliyor --> R1Deadlock’u kırmak için bu dört koşuldan herhangi birini bozmak yeterlidir. En pratik olanı Circular Wait’i engellemektir: tüm kaynakları sabit bir sırayla kilitlemek.
Race Condition
Birden fazla thread’in ortak veriye aynı anda erişmesi ve sonucun işlem sırasına bağlı olarak değişmesi durumudur. Çözümler: Mutex, Lock, Semaphore, atomic operations.
Mutex vs Semaphore sık sorulur
| Özellik | Mutex | Semaphore |
|---|---|---|
| Mantık | Kilitleme (locking) — critical section’a tek giriş | Sinyalleşme (signaling) — sayaçlı erişim kontrolü |
| Değer | İkili (kilitli / açık) | Sayaç (0..N) — N kaynağa aynı anda izin |
| Sahiplik | Var: kilidi alan thread açmak zorundadır | Yok: bir thread bekler, başka bir thread signal verebilir |
| İşlemler | lock() / unlock() | wait() (P, azalt) / signal() (V, artır) |
| Tipik kullanım | Ortak değişkeni koruma | Kaynak havuzu (10 bağlantılık pool), producer-consumer |
Binary semaphore (sayaç=1) mutex ile aynı mıdır?
Hayır. Davranışı benzer ama sahiplik farkı vardır: mutex’i yalnızca kilitleyen thread açabilir; binary semaphore’a herhangi bir thread signal verebilir. Bu yüzden semaphore thread’ler arası haberleşme/sinyalleşme için de kullanılır.
CPU Scheduling sık sorulur
Amaç: hazır (ready) kuyruğundaki process’lerden hangisinin CPU’yu alacağına karar vermek. İki tür vardır: Non-preemptive (process CPU’yu kendi bırakana kadar çalışır) ve Preemptive (OS, çalışan process’i kesip CPU’yu elinden alabilir).
| Algoritma | Mantık | Güçlü yanı | Zayıf yanı |
|---|---|---|---|
| FCFS (First Come First Served) | İlk gelen ilk çalışır | En basit | Convoy effect — uzun bir iş öne gelirse arkadaki kısa işler uzun süre bekler |
| SJF (Shortest Job First) | En kısa burst süresine sahip iş önce | Ortalama bekleme süresini minimize eder (teorik olarak optimal) | Burst süresi önceden bilinemez; uzun işler starvation yaşayabilir. Preemptive hâli: SRTF |
| Priority | En yüksek öncelikli process önce | Kritik işleri öne alır | Starvation; çözümü aging — bekleyenin önceliği zamanla artar |
| Round Robin | Herkese sabit time quantum (örn. 10 ms), süresi dolan kuyruğun sonuna | Adil, iyi tepki süresi — zaman paylaşımlı sistemlerin temeli | Quantum seçimi kritik |
Klasik soru — RR'de quantum çok küçük/büyük olursa?
Çok küçük olursa: Context switch sayısı patlar; CPU zamanının önemli kısmı işe değil, geçiş yüküne (register kaydetme, cache kaybı) harcanır → verim düşer.
Çok büyük olursa: RR, FCFS’e yaklaşır; etkileşimli işlerin tepki süresi bozulur.
İdeal quantum, context switch maliyetinden çok büyük ama tipik burst’lerden küçük seçilir.
Hesap örneği — hepsi t=0’da geliyor: P1 = 24 ms, P2 = 3 ms, P3 = 3 ms burst.
FCFS (geliş sırası P1,P2,P3): | P1 (0-24) | P2 (24-27) | P3 (27-30) |
Bekleme: P1=0, P2=24, P3=27 → ortalama (0+24+27)/3 = 17 ms
SJF (kısa önce: P2,P3,P1): | P2 (0-3) | P3 (3-6) | P1 (6-30) |
Bekleme: P2=0, P3=3, P1=6 → ortalama (0+3+6)/3 = 3 ms
RR (quantum=4): | P1 (0-4) | P2 (4-7) | P3 (7-10) | P1 (10-30) |
Bekleme: P1=6, P2=4, P3=7 → ortalama ≈ 5,7 ms
Aynı işler, yalnızca sıralama değişerek ortalama beklemeyi 17 ms’den 3 ms’ye düşürüyor — SJF’in “optimal” iddiasının somut hâli.
Bellek Yönetimi
- Sanal Bellek (Virtual Memory): RAM yetersiz kaldığında diskin bir bölümünün bellek gibi kullanılması.
- Paging (Sayfalama): Belleğin sabit boyutlu sayfalara bölünerek yönetilmesi.
Bölüm 9 — Ağ (Networking)
OSI Modeli (7 Katman)
Ağ iletişimini katmanlara ayıran teorik referans modeldir (ISO, 1984). Amacı: her katman yalnızca kendi işinden sorumlu olsun, alt katmanın nasıl çalıştığını bilmesin. Böylece bir katman değişse (Wi-Fi → Ethernet) üsttekiler etkilenmez.
Numaralandırma aşağıdan yukarıya doğrudur (1 = Fiziksel). Veri gönderirken 7’den 1’e iner, alırken 1’den 7’ye çıkar.
| # | Katman | Görevi | PDU | Adresleme | Protokoller | Cihaz |
|---|---|---|---|---|---|---|
| 7 | Application | Uygulamanın ağ ile konuştuğu katman | Data | — | HTTP(S), FTP, SMTP, DNS, SSH, DHCP | Gateway |
| 6 | Presentation | Veri formatı dönüşümü, şifreleme/deşifreleme (SSL/TLS), sıkıştırma, karakter kodlaması | Data | — | SSL/TLS, JPEG, ASCII, UTF-8, MPEG | — |
| 5 | Session | Oturum kurma, yönetme, sonlandırma; senkronizasyon ve checkpoint | Data | — | NetBIOS, RPC, SMB, PPTP | — |
| 4 | Transport | Uçtan uca güvenilir iletim, segmentasyon, akış kontrolü, hata kontrolü | Segment (TCP) / Datagram (UDP) | Port numarası | TCP, UDP | Firewall (L4) |
| 3 | Network | Mantıksal adresleme ve yönlendirme (routing) — paketi ağdan ağa taşır | Packet | IP adresi | IP, ICMP, ARP*, OSPF, BGP | Router, L3 Switch |
| 2 | Data Link | Aynı ağ içinde fiziksel adresleme, çerçeveleme, hata tespiti (CRC) | Frame | MAC adresi | Ethernet, PPP, Wi-Fi (802.11) | Switch, Bridge, NIC |
| 1 | Physical | Bitlerin elektrik/ışık/radyo sinyaline dönüşüp ortamda iletimi | Bit | — | Ethernet fiziksel katmanı, USB, Bluetooth | Hub, Repeater, kablo |
* ARP genelde Katman 2–3 arası kabul edilir (IP → MAC çözümlemesi).
Katman 2’nin iki alt katmanı: LLC (Logical Link Control — üst katmanla arayüz) ve MAC (Media Access Control — ortama erişim).
Ezber teknikleri
Yukarıdan aşağı (7→1): Uygulama, Sunum, Oturum, Taşıma, Ağ, Veri Bağlantı, Fiziksel
İngilizce (7→1): All People Seem To Need Data Processing
İngilizce (1→7): Please Do Not Throw Sausage Pizza Away
Türkçe (1→7): "Farklı Veriler Ağdan Taşınır, Oturum Sunumda Uygulanır."
Encapsulation (Kapsülleme) çok sorulur
Veri her katmanda bir başlık (header) eklenerek aşağı iner; karşı tarafta ters işlem (decapsulation) yapılır.
GÖNDEREN (aşağı iner) ALICI (yukarı çıkar)
───────────────────── ────────────────────
7-5 [ Data ] [ Data ]
4 [ TCP Header | Data ] = Segment [ TCP H | Data ]
3 [ IP H | TCP H | Data ] = Packet [ IP H | TCP H | Data ]
2 [ MAC H | IP H | TCP H | Data | CRC ] = Frame ...
1 0101110100101110... = Bit ...
Ezber: Data → Segment → Packet → Frame → Bit
OSI vs TCP/IP sık sorulur
- OSI: 7 katmanlı, teorik/referans model. Önce model tasarlandı, protokoller sonra düşünüldü. Öğretimde ve sorun tespitinde kullanılır.
- TCP/IP (DoD Modeli): 4 katmanlı, pratik model. Önce protokoller yazıldı, model sonra çıkarıldı. İnternet fiilen bunun üzerine kuruludur.
OSI (7 Katman) TCP/IP (4 Katman)
┌──────────────────────────┐ ┌──────────────────────────┐
│ 7. Application │ │ │
│ 6. Presentation │ ───► │ 4. Application │ HTTP, FTP, DNS, SMTP
│ 5. Session │ │ │
├──────────────────────────┤ ├──────────────────────────┤
│ 4. Transport │ ───► │ 3. Transport │ TCP, UDP
├──────────────────────────┤ ├──────────────────────────┤
│ 3. Network │ ───► │ 2. Internet │ IP, ICMP, ARP
├──────────────────────────┤ ├──────────────────────────┤
│ 2. Data Link │ ───► │ │
│ 1. Physical │ │ 1. Network Access │ Ethernet, Wi-Fi
└──────────────────────────┘ └──────────────────────────┘
| Kriter | OSI | TCP/IP |
|---|---|---|
| Katman sayısı | 7 | 4 (bazı kaynaklarda 5) |
| Niteliği | Teorik referans model | Pratik, uygulanan model |
| Geliştirme sırası | Model → protokol | Protokol → model |
| Geliştiren | ISO | DARPA / DoD |
| Katman bağımsızlığı | Katmanlar kesin ayrılmıştır | Katmanlar iç içe geçmiştir |
| Taşıma katmanı | Yalnızca bağlantı yönelimli tanımlar | Hem bağlantılı (TCP) hem bağlantısız (UDP) |
| Kullanım | Öğretim, referans, troubleshooting | İnternetin fiili standardı |
Sınavda sorulursa tek cümle
“OSI teorik ve 7 katmanlıdır, referans amaçlıdır; TCP/IP pratik ve 4 katmanlıdır, internet bunun üzerinde çalışır. TCP/IP’nin Uygulama katmanı OSI’nin 5-6-7’sine, Ağ Erişimi katmanı ise OSI’nin 1-2’sine karşılık gelir.”
Uçtan uca örnek: tarayıcıya www.site.com yazınca ne olur?
1. DNS sorgusu → alan adı IP'ye çevrilir (L7 Application, UDP:53)
2. TCP 3-way handshake: SYN → SYN-ACK → ACK (L4 Transport)
3. TLS handshake, şifreleme anahtarı belirlenir (L6 Presentation)
4. HTTP GET isteği oluşturulur (L7 Application)
5. Segmentlere bölünür, port eklenir (443) (L4 Transport)
6. IP başlığı eklenir, router yolu belirler (L3 Network)
7. MAC başlığı eklenir, switch aynı ağda iletir (L2 Data Link)
8. Bitler kablo/Wi-Fi üzerinden gider (L1 Physical)
9. Sunucuda ters sırayla (1→7) çözülür, yanıt döner
Bu senaryo, “OSI katmanlarını bir örnekle anlat” sorusunun en iyi cevabıdır.
Ağ Topolojileri
Ağdaki cihazların fiziksel/mantıksal yerleşimini ifade eder.
Tüm cihazlar tek bir ana kabloya (backbone) bağlıdır.
flowchart LR
A[PC1] --- HAT
B[PC2] --- HAT
C[PC3] --- HAT
D[PC4] --- HAT
HAT[====== Ana Kablo / Backbone ======]- Avantaj: Az kablo, ucuz, kurulumu basit.
- Dezavantaj: Ana kablo koparsa tüm ağ çöker; cihaz sayısı arttıkça çakışma (collision) artar; arıza tespiti zordur.
- Eski koaksiyel ağlarda kullanılırdı.
Tüm cihazlar merkezi bir cihaza (switch/hub) bağlıdır. Günümüzde en yaygın topoloji.
flowchart TD
S((Switch)) --- A[PC1]
S --- B[PC2]
S --- C[PC3]
S --- D[PC4]
S --- E[PC5]- Avantaj: Bir kablonun kopması sadece o cihazı etkiler; yönetim ve arıza tespiti kolay; cihaz eklemek basit.
- Dezavantaj: Merkezi cihaz arızalanırsa tüm ağ durur (single point of failure); bus’a göre daha çok kablo gerekir.
Her cihaz iki komşusuna bağlıdır; veri halka boyunca tek yönde dolaşır (genellikle token ile).
flowchart LR
A[PC1] --> B[PC2] --> C[PC3] --> D[PC4] --> A- Avantaj: Token sayesinde çakışma olmaz; trafik düzenlidir.
- Dezavantaj: Tek bir kablo/cihaz arızası halkayı bozabilir (çift halka ile yedeklilik sağlanır); cihaz ekleme ağı keser.
Her cihaz diğerlerine doğrudan bağlıdır (full mesh) veya kısmen bağlıdır (partial mesh).
flowchart TD
A[PC1] --- B[PC2]
A --- C[PC3]
A --- D[PC4]
B --- C
B --- D
C --- D- Avantaj: En yüksek yedeklilik (redundancy) — bir hat koparsa alternatif yol vardır.
- Dezavantaj: Çok pahalı ve karmaşık; full mesh’te n cihaz için \(\frac{n(n-1)}{2}\) bağlantı gerekir (10 cihaz → 45 kablo). Kritik omurga ağlarında ve askeri sistemlerde kullanılır.
Yıldız topolojilerin hiyerarşik birleşimidir.
flowchart TD
R((Kök Switch)) --- S1((Switch 1))
R --- S2((Switch 2))
S1 --- A[PC1]
S1 --- B[PC2]
S2 --- C[PC3]
S2 --- D[PC4]- Avantaj: Ölçeklenebilir; büyük kurumsal ağlara uygundur; bölümler hâlinde yönetilir.
- Dezavantaj: Kök (omurga) arızası alt dalları etkiler; kablolama maliyeti artar.
Birden fazla topolojinin birleşimidir (örn. yıldız + halka). Gerçek dünyadaki büyük ağların çoğu karmadır.
- Avantaj: Esnek — her bölüme uygun topoloji seçilebilir.
- Dezavantaj: Tasarımı ve yönetimi karmaşıktır.
| Topoloji | Maliyet | Güvenilirlik | Arıza Etkisi | Kullanım |
|---|---|---|---|---|
| Bus | Çok düşük | Düşük | Ana kablo → tüm ağ | Eski ağlar |
| Star | Orta | Orta-yüksek | Merkez cihaz → tüm ağ | LAN’lar (en yaygın) |
| Ring | Orta | Orta | Tek kopma → halka | Token Ring, MAN |
| Mesh | Çok yüksek | Çok yüksek | Minimum (alternatif yol) | Omurga, kritik sistemler |
| Tree | Yüksek | Orta | Kök → alt dallar | Kurumsal ağlar |
Hub vs Switch vs Router sık sorulur
| Özellik | Hub | Switch | Router |
|---|---|---|---|
| OSI Katmanı | 1 (Fiziksel) | 2 (Veri Bağı) | 3 (Ağ) |
| Kullandığı adres | Yok | MAC | IP |
| Çalışma şekli | Gelen sinyali tüm portlara kopyalar | MAC tablosuna bakarak yalnızca hedef porta iletir | Rota tablosuna göre ağlar arasında yönlendirir |
| Alan | Tek collision domain | Her port ayrı collision domain | Broadcast domain’leri ayırır |
| Görev | Aynı ağda kör dağıtım (artık kullanılmaz) | Aynı yerel ağ (LAN) içi iletim | Farklı ağları / interneti birbirine bağlama |
Neden hub artık kullanılmaz?
Her paketi herkese gönderir: bant genişliği israfı, çakışma (collision) ve güvenlik sorunu — herkes trafiği dinleyebilir. Switch, MAC tablosunu öğrenerek yalnızca ilgili porta iletir.
MAC vs IP Adresi sık sorulur
| Özellik | MAC | IP |
|---|---|---|
| Katman | L2 (Veri Bağı) | L3 (Ağ) |
| Nitelik | Fiziksel — üretici tarafından ağ kartına gömülür | Mantıksal — bağlanılan ağa göre atanır/değişir |
| Format | 48 bit, hex: AA:BB:CC:11:22:33 | IPv4: 32 bit, 192.168.1.10 |
| Kapsam | Yalnızca yerel ağ içi teslimat | Uçtan uca (ağlar arası) adresleme |
Analoji
MAC = kimlik numarası (değişmez), IP = ev adresi (taşınınca değişir). Paket yolculuk boyunca aynı hedef IP’yi taşır ama her ağ atlamasında (hop) kaynak/hedef MAC değişir.
ARP (Address Resolution Protocol) sık sorulur
Aynı yerel ağdaki bir cihazın IP adresinden MAC adresini bulur — L3 ile L2 arasındaki köprüdür. Çünkü yerel ağda çerçevelerin (frame) teslimatı MAC ile yapılır.
Cache’e bak
A,
192.168.1.5‘e paket gönderecek ama MAC’ini bilmiyor → önce kendi ARP cache‘ine bakar.Broadcast ile sor
Yoksa broadcast ARP isteği yayınlar (hedef MAC
FF:FF:FF:FF:FF:FF): “192.168.1.5 kimde?”Sahibi cevaplar
O IP’ye sahip cihaz unicast cevap verir: “Bende, MAC’im AA:BB:…”
Cache’e yaz ve gönder
A, cevabı ARP cache‘ine yazar (bir süre saklanır) ve çerçeveyi o MAC’e gönderir.
Hedef farklı ağdaysa?
ARP hedefin kendisine değil, varsayılan ağ geçidinin (router) IP’sine yapılır; paket router’ın MAC’ine teslim edilir, yönlendirmeyi router sürdürür.
Alt Ağlar (Subnetting) hesap sorusu
Büyük bir IP ağını daha küçük, yönetilebilir parçalara bölme işlemidir. Faydaları: broadcast trafiğini azaltır, güvenliği artırır (bölümler izole edilir), IP adres yönetimini kolaylaştırır.
- Subnet mask, adresin ağ ve host kısmını ayırır:
/24=255.255.255.0→ ilk 24 bit ağ, son 8 bit host. - Host sayısı:
Ağ adresi ve broadcast adresi düşüldüğü için -2 var. /24 → 254 host, /26 → 62 host.
Ağ adresini bulma — IP ile maske AND’lenir:
IP 192.168.1.130 → 11000000.10101000.00000001.10000010
Mask /26 (255.255.255.192) → 11111111.11111111.11111111.11000000
AND ─────────────────────────────────────────────────────
Ağ 192.168.1.128 → 11000000.10101000.00000001.10000000
Son oktet: 10000010 AND 11000000 = 10000000 = 128 → ağ adresi 192.168.1.128/26.
“İki IP aynı alt ağda mı?” — Her iki IP maskeyle AND’lenir; ağ adresleri eşitse aynı subnet’tir (doğrudan haberleşirler), değilse aradan router geçmesi gerekir.
192.168.1.130 AND /26 → 192.168.1.128
192.168.1.140 AND /26 → 192.168.1.128 → AYNI alt ağ ✓
192.168.1.200 AND /26 → 192.168.1.192 → FARKLI alt ağ ✗ (router gerekir)
Örnek soru: 192.168.10.0/24 ağı /26 ile alt ağlara bölünürse kaç alt ağ oluşur ve 192.168.10.70 hangisindedir?
Çözümü göster
/24→/26yani 2 bit ödünç alındı → \(22 = 4\) alt ağ, her biri \(26 - 2 = 62\) host.Alt ağlar 64’er artar:
.0,.64,.128,.192.70 sayısı 64–127 aralığında → 192.168.10.64/26
Bu alt ağın broadcast adresi
.127, kullanılabilir host aralığı.65–.126.
TCP vs UDP çok sık sorulur
| Özellik | TCP | UDP |
|---|---|---|
| Bağlantı | Bağlantılı (three-way handshake: SYN → SYN-ACK → ACK) | Bağlantısız |
| Güvenilirlik | Garanti (sıralı, eksiksiz, onaylı) | Garanti yok |
| Hız | Daha yavaş (overhead var) | Çok hızlı |
| Kontrol | Akış kontrolü + tıkanıklık kontrolü yapar | Yapmaz |
| Veri modeli | Byte akışı (stream) | Bağımsız datagram’lar |
| Başlık boyutu | 20+ byte | 8 byte |
| Kullanım | Web (HTTP), e-posta, dosya transferi | Canlı yayın, online oyun, VoIP, DNS sorguları |
TCP yerine UDP ne zaman kullanılır?
Hızın ve düşük gecikmenin veri kaybından daha önemli olduğu yerlerde. Canlı yayında kaybolan bir kare geri istenmez — istemek zaten anlamsızdır, çünkü o kare geldiğinde artık geçmiştir; akış devam eder.
TCP Bağlantı Kurulumu ve Kapanışı sık sorulur
sequenceDiagram
participant C as İstemci
participant S as Sunucu
Note over C,S: Kurulum — Three-Way Handshake
C->>S: SYN
S->>C: SYN-ACK
C->>S: ACK
Note over C,S: ... veri alışverişi ...
Note over C,S: Kapanış — Four-Way Termination
C->>S: FIN (işim bitti)
S->>C: ACK
S->>C: FIN (benim de bitti)
C->>S: ACK → TIME_WAIT- Kurulum neden 3 adım? Her iki taraf da hem “gönderebiliyorum” demeli hem karşı tarafın duyduğunu onaylamalı; ayrıca başlangıç sequence number’ları senkronize edilir.
- Kapanış neden 4 adım? Bağlantı çift yönlüdür; her yön ayrı kapatılır. Bir taraf FIN gönderdikten sonra karşı tarafın hâlâ gönderecek verisi olabilir (half-close) — bu yüzden FIN ve ACK’ler her zaman birleştirilemez.
- TIME_WAIT: Kapanışı başlatan taraf, son ACK’ten sonra bir süre (2×MSL) bekler — geciken paketlerin yeni bir bağlantıya karışmaması ve son ACK kaybolursa tekrar gönderilebilmesi için.
DNS (Domain Name System) sık sorulur
Alan adlarını (www.ornek.com) IP adreslerine çevirir — “internetin telefon rehberi”.
Alan adı hiyerarşisi: kök . → TLD (.com, .tr) → domain (ornek.com) → subdomain (blog.ornek.com).
Cache kontrolü
Tarayıcı ve işletim sistemi cache‘ine bakılır; kayıt varsa doğrudan kullanılır.
Recursive resolver
Yoksa istek recursive resolver‘a gider — ISP’nin sunucusu veya
8.8.8.8/1.1.1.1.Hiyerarşide gezinme
Resolver sırayla sorar: root server → ".com’a bakan TLD sunucusu şu" → TLD server → “ornek.com’un yetkili sunucusu şu” → authoritative server → IP’yi döner.
Cache’leme
Cevap, TTL süresi boyunca her katmanda cache’lenir.
DNS kayıt türleri:
| Kayıt | Görevi | Örnek |
|---|---|---|
| A | Alan adı → IPv4 adresi | ornek.com → 93.184.216.34 |
| AAAA | Alan adı → IPv6 adresi | ornek.com → 2606:2800::1 |
| CNAME | Takma ad → başka bir alan adı (alias) | www.ornek.com → ornek.com |
| MX | Alan adının mail sunucusu (öncelikli) | ornek.com → mail.ornek.com |
| NS | Alan adının yetkili DNS sunucusu | ornek.com → ns1.host.com |
| TXT | Serbest metin — doğrulama, SPF/DKIM | "v=spf1 ..." |
| PTR | Ters çözümleme: IP → alan adı | reverse DNS |
CNAME notu
CNAME başka bir isme işaret eder, IP’ye değil. Ayrıca kök alan adında (ornek.com apex) diğer kayıtlarla birlikte kullanılamaz — bu yüzden kökte A kaydı, www gibi subdomain’lerde CNAME yaygındır.
DHCP
Ağa bağlanan cihazlara otomatik IP ve ağ ayarları (maske, gateway, DNS) atar. 4 adım — DORA:
D iscover → istemci: "ortalıkta DHCP sunucusu var mı?" (broadcast)
O ffer → sunucu: "şu IP'yi sana verebilirim"
R equest → istemci: "kabul, o IP'yi istiyorum"
A cknowledge → sunucu: "tamam, kiralandı (lease)"
IPv4 vs IPv6 sık sorulur
| Özellik | IPv4 | IPv6 |
|---|---|---|
| Adres uzunluğu | 32 bit (~4,3 milyar adres) | 128 bit (~3,4×10³⁸ adres) |
| Gösterim | Noktalı onluk: 192.168.1.1 | Hex + iki nokta: 2001:0db8::1 (sıfır blokları :: ile kısaltılır) |
| Adres yetersizliği | Var → NAT zorunlu hâle geldi | Yok → her cihaza gerçek (public) adres |
| Broadcast | Var | Yok — yerine multicast/anycast |
| Yapılandırma | Elle veya DHCP | SLAAC ile otomatik (DHCPv6 de mümkün) |
| Güvenlik | IPsec opsiyonel/sonradan | IPsec tasarımın parçası |
| Başlık | Değişken uzunluk, checksum var | Sabit 40 byte, sade → yönlendirme daha hızlı |
IPv6'ya neden geçildi?
Temel neden IPv4 adreslerinin tükenmesidir; ayrıca NAT karmaşasını kaldırır, otomatik yapılandırma ve daha verimli yönlendirme sunar. Geçiş dönemi boyunca iki protokol birlikte çalışır (dual stack).
NAT, Firewall, VPN
- NAT: Yerel (özel) IP’lerin tek bir genel IP üzerinden internete çıkmasını sağlar.
- Firewall: Trafiği kurallara göre filtreler, yetkisiz erişimi engeller.
- VPN: İnternet üzerinden şifreli, güvenli bir tünel oluşturur.
Bölüm 10 — HTTP, REST ve Web
HTTP Metodları
| Metod | Ne yapar | Idempotent mi? | Güvenli mi? |
|---|---|---|---|
| GET | Veri alır, değiştirmez | ✅ | ✅ |
| POST | Yeni kaynak oluşturur / işlem başlatır | ❌ | ❌ |
| PUT | Kaynağı tamamen günceller | ✅ | ❌ |
| PATCH | Kaynağın bir kısmını günceller | Genelde ❌ | ❌ |
| DELETE | Kaynağı siler | ✅ | ❌ |
Idempotent = aynı isteği 10 kez göndermekle 1 kez göndermek arasında sonuç farkı yoktur.
HTTP Durum Kodları
200 OK → başarılı
201 Created → kaynak oluşturuldu
204 No Content → başarılı, gövde yok
301 Moved Permanently → kalıcı yönlendirme
400 Bad Request → hatalı istek
401 Unauthorized → kimlik doğrulama gerekli/başarısız
403 Forbidden → kimlik belli ama yetki yok
404 Not Found → kaynak bulunamadı
409 Conflict → çakışma
422 Unprocessable Content → doğrulama hatası
500 Internal Server Error → sunucu hatası
502 Bad Gateway → ara sunucu hatalı yanıt aldı
503 Service Unavailable → servis kullanılamıyor
401 ≠ 403
401 Unauthorized → “Kimliğini doğrula(yamadın).” Token yok, süresi dolmuş veya geçersiz.
403 Forbidden → “Kim olduğunu biliyorum ama buna yetkin yok.” Kimlik geçerli, izin yetersiz.
İsimlendirme kafa karıştırıcı: 401 aslında authentication, 403 ise authorization hatasıdır.
REST
Web servislerinin kaynaklar (resources) üzerinden standart HTTP prensipleriyle tasarlandığı mimari yaklaşımdır.
GET /users → tüm kullanıcıları listele
GET /users/15 → 15 numaralı kullanıcıyı getir
POST /users → yeni kullanıcı oluştur
PUT /users/15 → 15'i tamamen güncelle
DELETE /users/15 → 15'i sil
Stateless: Sunucu, istemcinin önceki isteğinin durumunu tutmak zorunda değildir; her istek gerekli tüm bilgiyi taşır. Bu, yatay ölçeklemeyi mümkün kılan özelliktir — herhangi bir sunucu herhangi bir isteği karşılayabilir.
REST vs SOAP
- REST: Hafif, JSON ağırlıklı, HTTP metodlarını kullanır, stateless.
- SOAP: XML tabanlı, katı kurallı bir protokol; daha ağır ama kurumsal güvenlik özellikleri (WS-Security) sunar.
HTTP vs HTTPS
HTTPS = HTTP + SSL/TLS şifrelemesi. Trafik şifrelenir; araya girme (man-in-the-middle) saldırıları engellenir. Portlar: HTTP 80, HTTPS 443.
Neden HTTPS?
Üç şeyi birden sağlar:
- Gizlilik (confidentiality) — trafik şifrelenir.
- Kimlik (authenticity) — sunucunun kimliği sertifikayla doğrulanır.
- Bütünlük (integrity) — verinin yolda değiştirilmediği garanti edilir.
TLS Handshake sık sorulur
Amaç: birbirini tanımayan iki tarafın, dinlenen bir hat üzerinde ortak bir gizli anahtarda anlaşması ve sunucunun kimliğinin doğrulanması.
ClientHello
İstemci desteklediği TLS sürümlerini, şifreleme takımlarını (cipher suite) ve rastgele bir değeri gönderir.
ServerHello + Sertifika
Sunucu şifreleme takımını seçer ve sertifikasını gönderir. İstemci sertifikayı, işletim sistemindeki güvenilir CA (Certificate Authority) zinciriyle doğrular — “bu gerçekten ornek.com mu?”
Anahtar değişimi
Taraflar (günümüzde genelde Diffie-Hellman ile) ortak bir oturum anahtarı üretir. Asimetrik kriptografi yalnızca bu aşamada kullanılır.
Finished
İki taraf da el sıkışmanın özetini şifreli olarak doğrular. Bundan sonra tüm veri, üretilen simetrik oturum anahtarıyla şifrelenir.
Neden anahtar değişimi asimetrik, veri trafiği simetrik?
Asimetrik şifreleme güvenli anahtar paylaşımını çözer ama yavaştır; simetrik şifreleme çok hızlıdır ama anahtarın önceden paylaşılmasını gerektirir. TLS ikisini birleştirir: asimetrik yolla bir simetrik anahtar kurulur, asıl trafik onunla şifrelenir.
HTTP/1.1 vs HTTP/2 vs HTTP/3 sık sorulur
| Özellik | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Taşıma | TCP | TCP | QUIC (UDP üzerinde) |
| Format | Düz metin | Binary frame’ler | Binary |
| Paralellik | Bağlantı başına sırayla 1 istek → tarayıcı 6 bağlantı açar | Tek bağlantıda multiplexing | Multiplexing + bağımsız stream’ler |
| Head-of-line blocking | Var (uygulama seviyesi) | Uygulamada çözüldü ama TCP seviyesinde sürer | Çözüldü — kayıp paket yalnızca kendi stream’ini bekletir |
| Ek özellikler | keep-alive | Header sıkıştırma (HPACK), server push | TLS gömülü, 0-RTT el sıkışma, bağlantı göçü (IP değişse de kopmaz) |
Özet cümle
HTTP/2 “tek TCP bağlantısında çok iş"i getirdi; HTTP/3 ise TCP’nin kendisinden kaynaklanan tıkanmayı aşmak için taşımayı QUIC/UDP’ye taşıdı.
Cookie, Session, JWT
| Nerede tutulur | Sunucu durum tutar mı | Tipik kullanım | |
|---|---|---|---|
| Cookie | Tarayıcıda; her istekle sunucuya gider | — | Session ID taşıma, tercihler |
| Session | Kullanıcı bilgisi sunucuda; istemciye sadece ID verilir | Evet (stateful) | Klasik web uygulamaları |
| JWT | Kullanıcı bilgisi imzalı token içinde istemcide | Hayır (stateless auth) | Mikroservisler, SPA, mobil |
Bölüm 11 — Yazılım Güvenliği
Authentication vs Authorization
Authentication (Kimlik Doğrulama)
“Sen kimsin?” — giriş aşaması. Şifre, token, biyometri.
Hata kodu: 401
Authorization (Yetkilendirme)
“Bunu yapmaya yetkin var mı?” — rol/izin kontrolü.
Hata kodu: 403
Yaygın Saldırılar ve Önlemler
| Saldırı | Ne yapar | Önlem |
|---|---|---|
| SQL Injection | Kullanıcı girdisi doğrudan SQL sorgusuna eklenince sorgunun yapısı değişir | Parameterized queries / prepared statements, ORM, input validation |
| XSS (Cross-Site Scripting) | Sayfaya zararlı JavaScript enjekte edilir | Girdilerin encode/sanitize edilmesi, CSP |
| CSRF | Kullanıcının mevcut oturum yetkileriyle, bilgisi dışında istek yaptırılır | CSRF token, SameSite cookie |
| DDoS | Çok sayıda kaynaktan aşırı istekle servis çökertilir | Rate limiting, CDN, WAF |
| Brute Force | Şifreler deneme-yanılmayla kırılır | Hesap kilitleme, CAPTCHA, güçlü şifre politikası |
Hashing, Encryption ve Encoding sık sorulur
Üçü de veriyi “okunamaz” hâle getirdiği için sürekli karıştırılıyor. Oysa amaçları tamamen farklı ve aralarındaki tek ayırt edici soru şu: geri döndürülebilir mi, döndürülebiliyorsa neye ihtiyaç var?
| Hashing | Encryption | Encoding | |
|---|---|---|---|
| Amaç | Bütünlük / doğrulama | Gizlilik | Uyumluluk / taşınabilirlik |
| Yön | Tek yönlü — geri dönüş yok | Çift yönlü | Çift yönlü |
| Geri çevirmek için | — (imkânsız) | Anahtar gerekir | Hiçbir şey — algoritma herkese açık |
| Çıktı boyutu | Sabit (SHA-256 → hep 256 bit) | Girdiyle orantılı | Girdiden biraz büyük (Base64 ≈ %33 fazla) |
| Güvenlik sağlar mı | Evet (doğrulama için) | Evet | Hayır — sıfır güvenlik |
| Örnek | SHA-256, bcrypt, Argon2 | AES, RSA, ChaCha20 | Base64, URL encoding, UTF-8, ASCII |
| Ters işlemin adı | (yok) | Decryption | Decoding |
Hashing "sifre123" → hash → a8f5f167f44f4964e6c998dee827110c → ✗ geri dönüş YOK
Encryption "sifre123" → encrypt → U2FsdGVkX1+9k2... ──decrypt(🔑)──→ "sifre123"
Encoding "sifre123" → encode → c2lmcmUxMjM= ──decode()────→ "sifre123"
En sık yapılan hata: Base64 şifreleme değildir
c2lmcmUxMjM= gizli görünür ama herkes tek satırda çözebilir — anahtar gerekmez, çünkü Base64 bir encoding‘dir, algoritması standarttır:
import base64
base64.b64decode("c2lmcmUxMjM=") # b'sifre123'
Encoding’in amacı gizlemek değil, veriyi taşınabilir kılmaktır: ikili (binary) veriyi yalnızca metin kabul eden bir kanaldan (JSON, e-posta, URL, HTTP başlığı) geçirmek. “Şifreledim, Base64’ledim” cümlesi sınavda da kod incelemesinde de yanlıştır.
Neden parola hash'lenir, encrypt edilmez?
Encrypt edilen veri, anahtar ele geçerse çözülür — sızıntıda tüm parolalar açığa çıkar. Hash tek yönlüdür: veritabanı sızsa bile parolalar geri çevrilemez. Doğrulama, girilen parolanın hash’i ile kayıtlı hash karşılaştırılarak yapılır; sistemin parolayı bilmesine zaten gerek yoktur.
Ek önlem — salt: Her parolaya rastgele bir değer eklenir. Böylece aynı parolalar farklı hash üretir ve rainbow table (önceden hesaplanmış hash sözlüğü) saldırıları etkisiz kalır.
Neden SHA-256 değil de bcrypt/Argon2? SHA-256 hızlı olacak şekilde tasarlanmıştır — saldırgan saniyede milyarlarca deneme yapabilir. bcrypt ve Argon2 ise kasıtlı olarak yavaştır ve maliyeti ayarlanabilir; parola hash’lemede istenen tam olarak budur.
Hangi kelime nerede kullanılır?
- Encrypt / Decrypt → şifreleme–çözme çifti. Anahtar var.
- Encode / Decode → kodlama–kod çözme çifti. Anahtar yok.
- Hash → tek yönlü. “Dehash” diye bir işlem yoktur; saldırgan hash’i çözmez, tahmin edip hash’leyerek karşılaştırır (brute force / rainbow table).
Türkçede üçü de “şifreleme” diye çevrildiği için karışıyor; sınavda İngilizce terimi kullanmak ayrımı kendiliğinden netleştiriyor.
Bonus: hashing'in parola dışındaki kullanımları
Hash yalnızca parola saklamak için değil, “bu veri değişti mi?” sorusunu ucuza cevaplamak için de kullanılır:
- Dosya bütünlüğü: İndirilen ISO’nun SHA-256 özeti siteyle aynı mı?
- Git: Her commit, içeriğinin hash’iyle adlandırılır — geçmişin değiştirilemez olmasının sebebi budur.
- Hash table: Anahtarı dizi indeksine çevirmek (bkz. Hash Table). Buradaki hash kriptografik olmak zorunda değildir, hızlı olması yeterlidir.
- Dijital imza: Belgenin tamamı değil, hash’i imzalanır — çok daha hızlıdır.
- Blok zinciri: Her blok bir öncekinin hash’ini taşır.
Dikkat: bu kullanımların hepsi bütünlük içindir, gizlilik için değil. Hash gizlemez, kanıtlar.
Simetrik vs Asimetrik Şifreleme
| Simetrik | Asimetrik | |
|---|---|---|
| Anahtar | Şifreleme ve çözme aynı anahtarla | Public key ile şifrele, private key ile çöz |
| Hız | Hızlı | Yavaş |
| Sorun | Anahtarın güvenli paylaşımı | Performans |
| Örnek | AES | RSA, ECDSA |
| Nerede | Asıl veri trafiği | HTTPS el sıkışması, dijital imza |
Pratikte ikisi birlikte kullanılır: asimetrik ile anahtar paylaşılır, iletişim simetrik ile devam eder.
Bölüm 12 — Yazılım Testi
Test Seviyeleri
- Unit Test: Tek bir fonksiyon/metod/modülün tek başına testi.
- Integration Test: Bileşenlerin birlikte doğru çalışmasının testi.
- System Test: Sistemin bütün olarak testi.
- Acceptance Test (UAT): Kullanıcı/iş gereksinimlerinin karşılandığının, genellikle müşteri tarafından kontrolü.
- Regression Test: Yeni değişikliklerin mevcut çalışan özellikleri bozup bozmadığının kontrolü.
Black Box vs White Box
- Black Box: İç yapı bilinmeden, yalnızca girdi-çıktı davranışına göre test.
- White Box: Kodun iç yapısı (dallanma, döngü, kod kapsamı) bilinerek test.
Test Piramidi
flowchart TD
E2E["E2E / UI Testleri (az sayıda, yavaş, pahalı)"] --> INT["Integration Testleri (orta)"]
INT --> UNIT["Unit Testler (çok sayıda, hızlı, ucuz)"]Çok sayıda unit test, daha az integration, en az E2E test tercih edilir. Sebep basit: bir hata ne kadar aşağıdaki katmanda yakalanırsa bulunması ve düzeltilmesi o kadar ucuzdur.
Verification vs Validation
- Verification: “Ürünü doğru mu yapıyoruz?” → belgelere/tasarıma uygunluk.
- Validation: ”Doğru ürünü mü yapıyoruz?" → gerçek kullanıcı ihtiyacını karşılama.
Bölüm 13 — Git ve Versiyon Kontrolü
Temel Komutlar
git clone <url> # depoyu indir
git status # durumu göster
git add <dosya> # değişikliği stage'e al
git commit -m "..." # kaydet
git push # uzak depoya gönder
git pull # uzak depodan al ve birleştir
git fetch # uzak değişiklikleri indir (birleştirmez)
git branch # dalları listele/oluştur
git checkout / switch # dal değiştir
git merge <dal> # dalı birleştir
git rebase <dal> # commit'leri başka dalın üzerine taşı
git stash # değişiklikleri geçici kaydet
Merge vs Rebase
Merge
İki dalı birleştirir; bir merge commit oluşturabilir. Geçmiş dallı görünür — ne zaman neyin birleştiğini gösterir.
Rebase
Dalın commit’lerini hedef dalın güncel ucunun üzerine taşır; lineer bir geçmiş oluşturur.
⚠️ Ortak/paylaşılan dallarda dikkatli kullanılmalıdır — commit hash’leri değişir.
Pull vs Fetch
fetch: Uzak değişiklikleri indirir, mevcut dalı değiştirmez. Güvenlidir; önce bakıp sonra karar verirsin.pull: Kabacafetch + merge(veyafetch + rebase) işlemidir.
Conflict (Çakışma)
Aynı dosyanın aynı satırlarının iki dalda farklı değiştirilmesiyle oluşur. Git hangi değişikliğin doğru olduğuna karar veremez; manuel çözülür, sonra commit edilir.
Bölüm 14 — Mimari, Cloud ve Dağıtık Sistemler
Monolith vs Microservices
- Monolith: Uygulama tek deploy edilebilir birimdir. Başlangıçta basittir; büyüdükçe bakım ve ölçekleme zorlaşır.
- Microservices: Sistem, bağımsız geliştirilen/deploy edilen küçük servislerden oluşur; servisler API (REST) veya mesajlaşma ile haberleşir.
Mikroservis avantajları
- Bağımsız deployment
- Bağımsız ölçekleme
- Takımların bağımsız çalışması
- Teknoloji çeşitliliği
Mikroservis dezavantajları
- Network karmaşıklığı
- Dağıtık sistem problemleri
- Monitoring/logging zorluğu
- Veri tutarlılığı problemleri
Vertical vs Horizontal Scaling
- Vertical (Dikey): Mevcut sunucuyu güçlendirmek (daha fazla CPU/RAM). Basit ama fiziksel bir sınırı vardır.
- Horizontal (Yatay): Daha fazla sunucu eklemek. Teorik olarak sınırsız ölçeklenir; load balancer gerektirir ve uygulamanın stateless olmasını ister.
Load Balancer
Gelen istekleri birden fazla sunucuya dağıtır; hiçbir sunucu aşırı yüklenmez, erişilebilirlik artar. Ayrıca sağlıksız sunucuları devre dışı bırakarak (health check) kesintiyi gizler.
Cache
Sık kullanılan verileri hızlı erişilen bir katmanda tutarak veritabanı/ağ yükünü azaltır (Redis, Memcached).
flowchart TD
C[Client] --> A[API]
A --> K{Cache'te var mı?}
K -- Evet --> H[Hızlı cevap döner]
K -- Hayır --> D[(Database)]
D --> Y[Cevap + cache'e yazılır]Message Queue
Servislerin asenkron haberleşmesini sağlar (RabbitMQ, Kafka).
flowchart LR
A[Service A] --> Q[[Message Queue]] --> B[Service B]Avantajları: asenkron işlem, servislerin birbirinden ayrılması (decoupling), trafik patlamalarının yönetilmesi (buffer), retry mekanizmaları.
Kafka ile RabbitMQ arasındaki farkı mesajın yaşam döngüsünden başlayarak anlattığım ayrı bir yazı var: Kafka mı RabbitMQ mu?
CDN (Content Delivery Network)
Statik içeriği (görsel, video, JS/CSS) kullanıcıya coğrafi olarak yakın sunuculardan servis ederek gecikmeyi azaltır.
Docker ve Container
- Container vs VM: VM kendi işletim sistemi çekirdeğini çalıştırır; container host kernel’ını paylaşır → çok daha hafiftir ve saniyeler içinde başlar. “Benim makinemde çalışıyordu” sorununu çözer.
- Bilinmesi gereken kavramlar: Image (şablon), Container (çalışan örnek), Dockerfile (image tarifi), Volume (kalıcı veri), Network, Registry (image deposu, örn. Docker Hub).
- Kubernetes: Çok sayıda container’ın dağıtım, ölçekleme ve yönetimini otomatikleştiren orkestrasyon platformudur.
CI/CD
- CI (Continuous Integration): Kodun sık sık ana dala birleştirilmesi; her birleştirmede otomatik derleme + test.
- CD (Continuous Delivery/Deployment): Testleri geçen kodun otomatik olarak canlıya (veya canlıya hazır hâle) taşınması.
- Araçlar: Jenkins, GitLab CI, GitHub Actions.
Bölüm 15 — Yapay Zeka ve Makine Öğrenmesi
AI vs ML vs DL
- AI (Yapay Zeka): En geniş kavram; makinelerin insan benzeri zekâ (öğrenme, problem çözme) göstermesini amaçlar.
- ML (Makine Öğrenmesi): AI’ın alt dalı; makinelerin açıkça programlanmadan verilerden öğrenmesi.
- DL (Derin Öğrenme): ML’in alt dalı; çok katmanlı yapay sinir ağları kullanır. Büyük veri ve karmaşık desenlerde (görüntü, doğal dil) çok başarılıdır.
flowchart TD
AI[Yapay Zeka - AI] --> ML[Makine Öğrenmesi - ML] --> DL[Derin Öğrenme - DL]Gözetimli ve Gözetimsiz Öğrenme
- Supervised (Gözetimli): Etiketli verilerle eğitim; model girdi-çıktı ilişkisini öğrenir.
- Classification (Sınıflandırma): Çıktı kategoriktir. Örn: spam / spam değil.
- Regression (Regresyon): Çıktı sayısaldır. Örn: evin metrekaresinden fiyat tahmini.
- Unsupervised (Gözetimsiz): Etiketsiz veride gizli yapı/desen/grup arar. En yaygın örnek: kümeleme (clustering) — müşterileri davranışa göre gruplamak.
Görüntü İşleme Görevleri: Classification, Detection, Segmentation
Üçü de gözetimli öğrenmedir ve sürekli karıştırılır. Ayrım, modelin ne kadar ayrıntı ürettiğidir:
| Görev | Cevapladığı soru | Çıktı | Örnek model |
|---|---|---|---|
| Classification | “Bu görüntüde ne var?” | Görüntünün tamamına tek etiket | ResNet, EfficientNet |
| Object Detection | “Ne var ve nerede?” | Sınıf + bounding box (konum) | YOLO, Faster R-CNN, SSD |
| Segmentation | “Hangi pikseller ona ait?” | Piksel düzeyinde maske | U-Net, Mask R-CNN |
Classification → [kedi] (konum yok)
Detection → [kedi @ (x, y, w, h)] (kutu var)
Segmentation → [kedi = şu piksel kümesi] (kenarı tam)
Detection modelleri ikiye ayrılır (sık sorulur):
- Two-stage (Faster R-CNN): Önce aday bölge üretir, sonra sınıflandırır. Daha hassas, daha yavaş.
- One-stage (YOLO, SSD): Tespiti tek geçişte yapar. Gerçek zamanlı uygulamaların tercihi.
Metrikler de farklıdır: sınıflandırmada accuracy/precision/recall/F1 kullanılırken, tespitte IoU (kutuların örtüşme oranı) ve mAP (mean Average Precision) kullanılır.
Bu üçünü ardışık da kullanabilirsiniz: önce detection ile ilgilenilen bölgeyi (ROI — Region of Interest) bulup kırpmak, sonra o küçük bölgeyi classification’a vermek. Böylece sınıflandırıcı, tüm karenin düşük çözünürlüğü yerine küçük bir bölgeyi tam detayıyla inceler. Bitirme tezimdeki kademeli mimari tam olarak budur.
Overfitting ve Underfitting
Overfitting
Model eğitim verisini ezberler; yeni veride kötü performans gösterir.
Nedenler: model çok karmaşık, veri az, çok uzun eğitim.
Çözüm: daha çok veri, regularization, dropout, erken durdurma, cross-validation.
Underfitting
Model eğitim verisindeki ilişkiyi bile öğrenemez.
Neden: model çok basit, özellikler yetersiz.
Çözüm: daha karmaşık model, daha iyi özellikler, daha uzun eğitim.
Bias vs Variance
Yüksek bias → model fazla basit → underfitting (iyi öğrenemedi)
Yüksek variance → veriye fazla duyarlı → overfitting (ezberledi)
Amaç ikisi arasında denge kurmaktır: bias-variance tradeoff.
Train / Validation / Test Ayrımı
Training → modeli eğitmek
Validation → hiperparametre / model seçmek
Test → final performansı ölçmek (eğitimde ASLA kullanılmaz)
Confusion Matrix ve Metrikler
Tahmin
Pozitif Negatif
Gerçek Pozitif TP FN
Gerçek Negatif FP TN
- Precision — “Pozitif dediklerimin kaçı gerçekten pozitif?”
- Recall — “Gerçek pozitiflerin kaçını yakaladım?”
- F1 Score — Precision ve Recall’un harmonik ortalaması.
Ne zaman hangisi?
Yanlış alarmın maliyeti yüksekse → Precision. Spam filtresi: önemli bir maili spam’e atmak kabul edilemez.
Kaçırmanın maliyeti yüksekse → Recall. Kanser taraması: hasta bir kişiyi atlamak kabul edilemez.
Embedding
Metin, kelime, resim gibi verilerin anlamını/özelliklerini temsil eden sayısal vektöre dönüştürülmesidir. Anlamca benzer veriler vektör uzayında birbirine yakın konumlanır. Vektör veritabanları bu vektörler üzerinde benzerlik araması yapar.
LLM, Token ve RAG
- LLM (Large Language Model): Büyük miktarda metinle eğitilmiş; metin üretme/anlama görevlerini yapan model.
- Token: LLM’in metni işlediği temel parça; her zaman tam bir kelime olmak zorunda değildir.
- RAG (Retrieval-Augmented Generation): LLM’in cevap üretmeden önce harici bir bilgi kaynağından ilgili bilgileri getirmesi yaklaşımı.
flowchart TD
A[Doküman] --> B[Chunking - parçalama]
B --> C[Embedding]
C --> D[(Vector Database)]
E[Kullanıcı Sorusu] --> F[Similarity Search]
D --> F
F --> G[İlgili Dokümanlar]
G --> H[LLM]
E --> H
H --> I[Cevap]RAG neden kullanılır? Güncel/özel verilere erişim, kuruma özel dokümanlarla çalışma, halüsinasyonları azaltma ve modeli yeniden eğitmeden bilgi kaynağını değiştirebilme.
Bölüm 16 — Programlama Temelleri
Derleyici vs Yorumlayıcı
- Compiler: Kodun tamamını önceden makine koduna çevirir (C, C++, Go); çalışması hızlıdır.
- Interpreter: Kodu satır satır çalıştırır (Python, JavaScript); esnektir ama genellikle daha yavaştır.
- Ara model: Java → bytecode → JVM üzerinde çalışır (JIT ile sıcak yollar makine koduna derlenir).
Compile-time vs Runtime
- Compile-time: Derleme sırasında yakalanan hatalar — sözdizimi, tip hataları (statik dillerde).
- Runtime: Program çalışırken oluşan hatalar — sıfıra bölme, null referans, dosya bulunamadı.
Pass by Value vs Pass by Reference
- Value: Fonksiyona kopya gönderilir; içerideki değişiklik orijinali etkilemez.
- Reference: Adres gönderilir; değişiklik orijinali de etkiler.
Garbage Collection
Kullanılmayan bellek alanlarının otomatik tespit edilip serbest bırakılmasıdır (Java, C#, Python, Go). C/C++‘ta bellek yönetimi geliştiricinin sorumluluğundadır.
Synchronous vs Asynchronous
- Senkron: İşlem bitene kadar beklenir; sıradaki işlem bloklanır.
- Asenkron: İşlem başlatılır, sonucu beklemeden devam edilir; sonuç geldiğinde (callback/promise/async-await) işlenir. I/O yoğun işlerde verimlidir.
Bölüm 17 — Python Kod Örnekleri
Sınavda elle yazdırılabilecek klasikler. Hepsini ezberlemek değil, mantığını anlatabilmek hedef.
Bubble Sort
def bubble_sort(liste):
n = len(liste)
for i in range(n - 1):
for j in range(n - 1 - i):
if liste[j] > liste[j + 1]:
liste[j], liste[j + 1] = liste[j + 1], liste[j] # yer değiştir
return liste
print(bubble_sort([5, 2, 9, 1, 7])) # [1, 2, 5, 7, 9]
- Time: O(n²) — iç içe iki döngü. Space: O(1) (yerinde sıralama).
- Optimizasyon: Bir turda hiç takas olmadıysa liste sıralıdır, erken çıkılabilir → en iyi durum O(n).
Asal sayıları listeleme
def asal_mi(sayi):
if sayi < 2:
return False
for i in range(2, int(sayi ** 0.5) + 1): # kareköke kadar bakmak yeterli
if sayi % i == 0:
return False
return True
n = int(input("Bir sayı girin: "))
for sayi in range(2, n + 1):
if asal_mi(sayi):
print(sayi, end=" ")
Örnek: girdi 20 → çıktı 2 3 5 7 11 13 17 19
Neden kareköke kadar?
Bir sayının karekökünden büyük bir böleni varsa, mutlaka karekökünden küçük bir eş böleni de vardır (çünkü a × b = n ve a > √n ise b < √n). Bu yüzden \(\sqrt{n}\)’e kadar kontrol etmek yeterlidir — O(n) yerine \(O(\sqrt{n})\).
Fibonacci
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
n = int(input("Kaç Fibonacci sayısı? "))
for i in range(n):
print(fibonacci(i), end=" ") # 0 1 1 2 3 5 8 13 ...
Zaman O(n), bellek O(1). Pratikte tercih edilecek çözüm budur.
def fib(n):
if n <= 1: # base case
return n
return fib(n - 1) + fib(n - 2)
Klasik sınav sorusudur ama verimsizdir: her çağrı iki çağrı üretir ve aynı değerler tekrar tekrar hesaplanır.
Zaman O(2ⁿ), bellek O(n) (call stack derinliği).
from functools import lru_cache
@lru_cache(maxsize=None)
def fib_hizli(n):
if n <= 1:
return n
return fib_hizli(n - 1) + fib_hizli(n - 2)
Recursive yazımın okunabilirliğini korur, tekrar eden hesapları önler → O(n).
Sınav sorusu
“Recursive fib‘in karmaşıklığı nedir, nasıl optimize edilir?” → Zaman O(2ⁿ), bellek O(n). Optimizasyon: memoization (hesaplananı sakla) veya iteratif çözüm → O(n).
Girilen sayıları toplama
adet = int(input("Kaç sayı gireceksiniz? "))
toplam = 0
for i in range(adet):
sayi = float(input(f"{i + 1}. sayı: "))
toplam += sayi
print("Toplam:", toplam)
toplam = 0
while True:
girdi = input("Sayı girin (bitirmek için Enter): ")
if girdi == "":
break
toplam += float(girdi)
print("Toplam:", toplam)
sayilar = input("Sayıları boşlukla girin: ").split() # "3 5 8" → ['3','5','8']
print("Toplam:", sum(int(s) for s in sayilar))
Metni ters çevirme ve palindrom
metin = input("Bir metin girin: ")
# Yöntem 1: Dilimleme (Pythonic)
print(metin[::-1])
# Yöntem 2: Döngü ile (mantığını göstermek için)
ters = ""
for karakter in metin:
ters = karakter + ters # her karakteri başa ekle
print(ters)
# Yöntem 3: reversed() ile
print("".join(reversed(metin)))
# Palindrom kontrolü — ters çevirmenin doğrudan devamı
metin = input("Metin girin: ").lower().replace(" ", "")
if metin == metin[::-1]:
print("Palindrom") # örn: "kayak", "ey edip adanada pide ye"
else:
print("Palindrom değil")
Faktöriyel
# İteratif
def faktoriyel(n):
sonuc = 1
for i in range(2, n + 1):
sonuc *= i
return sonuc
# Recursive
def faktoriyel_r(n):
if n <= 1: # base case
return 1
return n * faktoriyel_r(n - 1)
print(faktoriyel(5)) # 120
Kısa klasikler
En büyük/küçük, tek-çift, rakam toplamı, FizzBuzz
# --- Listede en büyük / en küçük ---
sayilar = [4, 12, 7, 1, 9]
print(max(sayilar), min(sayilar)) # hazır fonksiyonla
en_buyuk = sayilar[0] # döngüyle (mantık sorulursa)
for s in sayilar:
if s > en_buyuk:
en_buyuk = s
print(en_buyuk) # O(n)
# --- Tek / çift ---
sayi = int(input("Sayı girin: "))
print("Çift" if sayi % 2 == 0 else "Tek")
# --- Rakamların toplamı ---
sayi = int(input("Sayı girin: "))
toplam = 0
while sayi > 0:
toplam += sayi % 10 # son rakamı al
sayi //= 10 # son rakamı at
print("Rakamlar toplamı:", toplam) # 1234 → 10
# --- FizzBuzz ---
for i in range(1, 101):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
Kod okuma sorusu
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
for j in range(i + 1, len(numbers)):
print(numbers[i], numbers[j])
Bu kod ne yapar, karmaşıklığı nedir?
Listedeki tüm ikili kombinasyonları yazdırır (sıra önemsiz, tekrar yok) — toplam \(\binom{5}{2} = 10\) satır. İç içe iki döngü olduğu için karmaşıklık O(n²).
j‘nin i + 1‘den başlaması, hem (1,2) hem (2,1) çiftinin yazılmasını ve bir elemanın kendisiyle eşleşmesini engeller.
Bölüm 18 — Senaryo ve Mülakat Soruları
“Bitirme tezinizden bahseder misiniz?” kesin sorulur
Bu sorunun kaçma ihtimali yok ve sınavın en kolay puan alınacak yeri, çünkü konuyu jüriden daha iyi bilen tek kişi benim. Tehlike, dağınık anlatmak. O yüzden üç katmanlı hazırlanıyorum: bir cümlelik tanım, 30 saniyelik özet, sonra derinleşme.
Tezin tam adı:
Derin Öğrenme Yöntemleri ile Akıllı Telefon Üretim Hatalarının Tespiti
30 saniyelik cevap (ezberlenecek olan bu)
“Cep telefonu montaj hattında, otomatik vidalama sırasında cihaz yanlış konumlandığında batarya hasar görüyor ve pahalı ekipman kaybı yaşanıyordu; mevcut mekanik çözümler bunu önleyemiyordu. Ben de derin öğrenme ve görüntü işleme ile, montaj istasyonundaki bir mobil cihazın kamerasını kullanan, düşük maliyetli ve esnek bir otomatik hata tespit sistemi geliştirdim.
Tespiti iki aşamalı kademeli bir mimariyle yapıyorum: önce YOLOv11 nesne tespit modeli telefon üzerindeki vida deliklerini buluyor ve yalnızca o bölgeleri (ROI) kırpıyor; ardından bir sınıflandırma modeli bu bölgeler üzerinden montaj hatasını belirliyor. Hata bulunduğunda operatör anlık uyarılıyor ve hatalı süreç devam etmeden durduruluyor.
Sistem DLaaS (Deep Learning as a Service) yaklaşımıyla kurgulandı ve 2 saniyenin altında yanıt süresi hedefleniyor. Üniversite–sanayi iş birliği kapsamında, gerçek bir endüstriyel probleme çözüm üretti.”
Sistem mimarisi
flowchart LR
K["Montaj istasyonu<br/>mobil cihaz kamerası"] -->|"USB — ADB"| P["Go proxy"]
P -->|HTTP| S["Python FastAPI<br/>yapay zeka sunucusu"]
subgraph AI ["İki aşamalı kademeli model"]
direction TB
Y["1. YOLOv11<br/>vida deliği tespiti"] --> R["ROI kırpma"]
R --> C["2. Sınıflandırma<br/>hatalı / hatasız"]
end
S --> Y
C -->|sonuç| P
P --> O["Operatör uyarısı<br/>süreci durdur"]
M["Merkezi yönetim<br/>uygulaması"] -.->|"uzaktan yönetim<br/>durum takibi"| P| Katman | Teknoloji | Neden |
|---|---|---|
| Görüntü kaynağı | Montaj istasyonundaki mobil cihaz kamerası | Hazır, ucuz, esnek donanım — endüstriyel kamera altyapısı gerektirmez |
| Aktarım | USB kablo + ADB (Android Debug Bridge) | Kablosuz ağın gecikmesi ve kararsızlığı yok; fabrika ortamında güvenilir |
| Ara katman | Go ile yazılmış proxy | Eşzamanlı cihaz yönetimi ve I/O yoğun aktarım; tek binary olarak dağıtım |
| Model sunucusu | Python + FastAPI | Derin öğrenme ekosistemi Python’da; FastAPI asenkron ve hızlı |
| Yönetim | Merkezi yönetim uygulaması | Cihazların uzaktan yönetimi ve durum takibi |
Hazırlanılması gereken takip soruları
Jüri asıl burayı sorar — “ne yaptın"ı değil, “neden böyle yaptın"ı.
Neden tek aşamalı değil de iki aşamalı (kademeli) mimari?
Çünkü iki farklı problem var ve tek modele ikisini birden yaptırmak her ikisini de kötüleştirir:
- Nerede? — Vida delikleri görüntünün neresinde? Bu bir konumlandırma problemi, YOLO’nun işi.
- Hatalı mı? — O delikteki montaj doğru mu? Bu bir ayırt etme problemi ve ince detay gerektirir.
Tek aşamalı bir detektör, tüm kareyi sabit ve düşük bir çözünürlüğe indirdiği için küçük kusurları ayırt edecek detayı kaybeder. ROI’yi kırpıp sınıflandırıcıya vermek, o küçük bölgeyi tam çözünürlükte incelemeyi sağlar.
Ayrıca mühendislik açısından: iki model bağımsız eğitilir, bağımsız güncellenir; yeni bir hata tipi eklemek için sadece sınıflandırıcıyı yeniden eğitmek yeterlidir, tespit modeline dokunulmaz.
Object detection ile classification arasındaki fark nedir?
- Classification (sınıflandırma): Görüntünün tamamına tek bir etiket verir — “bu resimde kedi var”. Konum bilgisi yok.
- Object detection (nesne tespiti): Nesnelerin hem sınıfını hem konumunu (bounding box) verir — “şurada, şu koordinatlarda bir kedi var”. YOLO bu gruptadır.
- Segmentation: Piksel düzeyinde ayırır — hangi pikseller kediye ait.
Tezimde ikisi de var, ama sırayla: önce detection (nerede?), sonra classification (hatalı mı?). (Bkz. Gözetimli ve Gözetimsiz Öğrenme — ikisi de gözetimli öğrenmedir, etiketli veriyle eğitilir.)
Neden YOLO? Başka detektör olmaz mıydı?
Nesne tespit modelleri ikiye ayrılır:
- Two-stage (Faster R-CNN gibi): Önce aday bölgeler üretir, sonra sınıflandırır. Genelde daha doğru ama yavaş.
- One-stage (YOLO, SSD): Tespiti tek geçişte yapar. Biraz daha az hassas olabilir ama çok daha hızlı.
Benim 2 saniyelik uçtan uca bütçem var ve bunun içinde ağ aktarımı, iki model çıkarımı ve uyarı da var. Bu yüzden one-stage şart; YOLO da bu ailenin en olgun ve en iyi desteklenen üyesi. YOLOv11‘i güncel sürüm olduğu ve hazır ön-eğitimli ağırlıklarla transfer learning’i kolaylaştırdığı için seçtim.
Modelin başarısını neyle ölçtün? Accuracy yeterli mi?
Hayır, accuracy tek başına yanıltıcı — çünkü veri dengesiz: hatalı montaj, sağlam montajdan çok daha nadir. Hiç hata bulmayan bir model bile %99 accuracy verebilir.
Bu problemde kaçırmanın (False Negative) maliyeti çok yüksek: hatalı bir telefon hatta devam ederse batarya hasar görüyor ve ekipman zarar görüyor. Yanlış alarmın maliyeti ise düşük — operatör bakar, geçer.
Dolayısıyla öncelik Recall‘dadır; Precision’dan bir miktar ödün verilebilir. Genel tabloyu görmek için F1 ve confusion matrix birlikte raporlanır. (Bkz. Confusion Matrix ve Metrikler — bu, oradaki “kanser taraması” örneğinin endüstriyel karşılığı.)
Nesne tespiti tarafında ise standart metrik mAP (mean Average Precision) ve IoU eşiğidir.
Veri dengesizliği ve az veri sorununu nasıl çözdün?
Üretim hattında hatalı örnek doğal olarak az. Kullanılabilecek yöntemler:
- Data augmentation: Döndürme, parlaklık/kontrast değişimi, gürültü ekleme — özellikle fabrika aydınlatmasının değişkenliğini taklit etmek için değerli.
- Transfer learning: Sıfırdan eğitmek yerine ön-eğitimli ağırlıklardan başlamak; az veriyle yüksek başarı.
- Class weight / oversampling: Azınlık sınıfına daha fazla ağırlık vermek.
- ROI kırpma da bunu destekler: Model tüm telefonu değil, küçük ve standart bir bölgeyi öğrendiği için problem basitleşir ve daha az veriyle öğrenilir.
(Bkz. Overfitting ve Underfitting — az veriyle çalışırken asıl risk ezberlemedir.)
2 saniyenin altı nasıl sağlanıyor? Darboğaz nerede?
Uçtan uca süre şu parçalardan oluşur: görüntü yakalama → USB aktarımı → YOLO çıkarımı → ROI kırpma → sınıflandırma → sonucun dönüşü.
- En büyük kazanç ROI’den geliyor: sınıflandırma tüm kare üzerinde değil, küçük bir kırpılmış bölge üzerinde çalışıyor.
- Aktarımın USB/ADB üzerinden olması, kablosuz ağ gecikmesini ve değişkenliğini denklemden çıkarıyor.
- Model sunucusu ayrı bir makinede olduğu için ağır çıkarım işi mobil cihazın sınırlı donanımından alınıyor — DLaaS yaklaşımının somut faydası bu.
Ölçmeden optimize etmemek gerektiği için önce hangi adımın ne kadar sürdüğü profillenir. (Bkz. “Bir API çok yavaş çalışıyor” — aynı yöntem.)
DLaaS (Deep Learning as a Service) ne demek?
Modeli her cihaza gömmek yerine, merkezi bir sunucuda servis olarak sunmaktır. İstemci sadece görüntüyü gönderir, sonucu alır.
Avantajları:
- Model güncellemesi tek yerden yapılır; sahadaki onlarca cihaza tek tek dağıtım gerekmez.
- Pahalı donanım (GPU) tek noktada toplanır, tüm istasyonlar paylaşır.
- İstemci tarafı ucuz ve basit kalır.
Bedeli: ağ bağımlılığı ve gecikme. Bu yüzden aktarım USB üzerinden ve yerel ağda tutuldu. Mimari olarak bu, mikroservis mantığının yapay zekâ tarafındaki karşılığıdır.
Bu çalışmayı nasıl devam ettirirsin? (Doktora bağlantısı)
Bu soru genelde “neden doktora?” sorusunun kılık değiştirmiş hâlidir; tezle gelecek planını bağlamak gerekir. Doğal devam yönleri:
Anomali tespiti (anomaly detection): Bilinen hata tiplerini sınıflandırmak yerine, “normalden sapma"yı öğrenmek — böylece daha önce hiç görülmemiş hata tipleri de yakalanır. Endüstride asıl zor problem budur, çünkü hatalı veri her zaman azdır.
Edge deployment: Modeli quantization/distillation ile küçültüp doğrudan cihazda çalıştırmak, ağ bağımlılığını kaldırmak.
Açıklanabilirlik (XAI): Operatöre yalnızca “hatalı” demek yerine nerede ve neden hatalı olduğunu göstermek — üretim ortamında güven için kritik.
Aktif öğrenme: Modelin kararsız kaldığı örnekleri operatöre sorup etiketleterek veri setini sürekli büyütmek.
Anlatırken dikkat
Teknoloji listesi saymak (Go, FastAPI, ADB, YOLO…) tek başına puan getirmiyor; jüri problem → çözüm → gerekçe zincirini duymak istiyor. Her teknolojiyi “neden onu seçtim” cümlesiyle birlikte söylemek, aynı bilgiyi iki kat değerli hâle getiriyor.
Ayrıca çalışmanın üniversite–sanayi iş birliği kapsamında, gerçek bir üretim hattındaki gerçek bir problem için yapıldığını mutlaka vurgulamak gerekiyor — akademik bir oyuncak proje değil.
“Kullanıcı sayısı 10.000’den 1.000.000’a çıktı. Sistemi nasıl ölçeklersin?”
Cevapta geçmesi beklenen kavramlar, kabaca uygulama sırasıyla:
Load Balancer → Horizontal Scaling → Caching (Redis) → Database Index
→ Read Replica → Message Queue → CDN → Database Sharding
En ucuzdan en pahalıya doğru ilerlemek doğru yaklaşımdır: önce ölç, sonra cache ve index gibi düşük maliyetli kazançları al, sharding’i en sona bırak.
“Bir API çok yavaş çalışıyor. Nereden başlarsın?”
Ölç, tahmin etme
Response time nedir, hangi endpoint yavaş? Ölçmeden yapılan optimizasyon şans oyunudur.
Log / metric / tracing
Darboğaz nerede? Dağıtık izleme (tracing) hangi adımda zaman kaybedildiğini gösterir.
Database sorgularını incele
Yavaş sorgu var mı?
EXPLAINile sorgu planına bak.Index kontrolü
Eksik index var mı? Full scan yapan sorgu var mı?
Network latency
Dış servis çağrıları mı yavaş? Timeout ve retry politikaları nasıl?
Cache değerlendir
Tekrar eden sorgular cache’lenebilir mi?
Profiling
Kodda hangi fonksiyon zaman yiyor?
Darboğazı optimize et
Ve tekrar ölç — düzeldiğini doğrula.
“SQL mi NoSQL mi?”
Tek doğru cevap yok — gerekçelendirme bekleniyor:
- Güçlü ilişkiler, ACID, karmaşık sorgular, net şema → SQL
- Büyük ölçek, esnek şema, dağıtık sistem, basit erişim desenleri → NoSQL
Bölüm 19 — Bilinmesi Gereken Karşılaştırmalar
Sınav öncesi her çifti 2-3 cümleyle açıklayabilecek durumda olmak gerekiyor. Kendi kontrol listem:
Kontrol listesi — 60+ karşılaştırma
Yapay zekâ / ML
- AI vs ML vs DL
- Supervised vs Unsupervised
- Classification vs Regression
- Overfitting vs Underfitting
- Precision vs Recall
- Classification vs Detection vs Segmentation
- One-stage (YOLO) vs Two-stage (Faster R-CNN) detektör
Veri yapıları ve algoritmalar
- Array vs Linked List
- Stack vs Queue
- DFS vs BFS
- Preorder vs Inorder vs Postorder
- Recursion vs İterasyon
İşletim sistemleri
- Process vs Thread
- Concurrency vs Parallelism
- Mutex vs Semaphore
- FCFS vs SJF vs Round Robin
- Preemptive vs Non-preemptive
Veritabanı
- SQL vs NoSQL
- Big Data’nın 5 V’si (Volume, Velocity, Variety, Veracity, Value)
- ACID vs BASE
- CAP: C vs A vs P
- DELETE vs TRUNCATE vs DROP
- WHERE vs HAVING
- 1NF vs 2NF vs 3NF vs BCNF
- Cache vs Database
Ağ ve web
- TCP vs UDP
- HTTP vs HTTPS
- GET vs POST
- PUT vs PATCH
- 401 vs 403
- REST vs SOAP
- OSI vs TCP/IP (katman eşleşmesiyle)
- Hub vs Switch vs Router
- MAC vs IP
- IPv4 vs IPv6
- HTTP/1.1 vs HTTP/2 vs HTTP/3
- TCP açılış (SYN) vs kapanış (FIN)
Güvenlik
- Authentication vs Authorization
- Hashing vs Encryption vs Encoding
- Encrypt/Decrypt vs Encode/Decode (Base64 neden şifreleme değil?)
- Simetrik vs Asimetrik şifreleme
Mimari
- Monolith vs Microservices
- Vertical vs Horizontal Scaling
- Synchronous vs Asynchronous
- Container vs VM
Yazılım mühendisliği
- Waterfall vs Scrum
- Verification vs Validation
- Unit vs Integration vs E2E
- Black Box vs White Box
- Coupling vs Cohesion
- Interface vs Abstract Class
- Composition vs Inheritance
- Git Merge vs Rebase
- Git Pull vs Fetch
Dil ve derleme
- Compiler vs Interpreter
- Compile-time vs Runtime
- Pass by Value vs Pass by Reference
Teori ve donanım
DFA vs NFA
Regular vs Context-Free
Decidable vs Recursively Enumerable
AND/OR vs NAND/NOR (evrensellik)
MUX vs DEMUX (ve n seçme hattı → 2ⁿ giriş kuralı)
XOR vs XNOR
Two’s complement vs işaret biti
Bölüm 20 — “Neden?” Soruları
Tanım ezberi yetmez; sınavlar gerekçe ister. Her başlığı açmadan önce kendi cevabını kur, sonra karşılaştır.
Neden HashMap O(1)?
Hash fonksiyonu anahtarı doğrudan bir dizi indeksine çevirir; arama yapılmaz, hücreye doğrudan gidilir. Çakışma çok olursa zincirler uzar ve en kötü durumda O(n)’e düşer.
Neden Binary Search O(log n)?
Her adımda problem boyutu yarıya iner; n → 1’e inmek \(\log_2 n\) adım sürer. Ön şart: liste sıralı olmalı.
Neden index sorguyu hızlandırır? Neden her sütuna koymayız?
B-Tree yapısı sayesinde full scan (O(n)) yerine \(O(\log n)\) erişim sağlar. Ama her yazma işleminde tüm index’ler de güncellenir → yazma yavaşlar, disk kullanımı artar.
Neden NoSQL kullanırım?
Esnek şema, yatay ölçekleme ve yüksek hacimli/dağıtık veri ihtiyacı olduğunda; katı ilişkiler ve anlık tutarlılık kritik değilse.
Neden mikroservis tercih ederim?
Bağımsız deploy/ölçekleme ve takım özerkliği gerektiğinde. Karşılığında dağıtık sistem karmaşıklığını (network, tutarlılık, gözlemlenebilirlik) kabul ederim.
Neden thread, process'ten ucuz?
Thread mevcut process’in belleğini paylaşır; yeni adres alanı ve sayfa tabloları oluşturulmaz, context switch daha hafiftir.
Neden HTTPS?
Trafiği şifreler (gizlilik), sunucuyu sertifikayla doğrular (kimlik), verinin değişmediğini garanti eder (bütünlük).
Neden parola hash'lenir, encrypt edilmez?
Hash tek yönlüdür; veritabanı sızsa bile parolalar geri çözülemez. Encrypt edilseydi anahtar sızdığında hepsi çözülürdü. Salt eklenerek rainbow table saldırıları da engellenir.
Neden overfitting oluşur?
Model kapasitesi veriye göre fazla büyükse veya veri azsa, model genel deseni değil gürültüyü öğrenir — yani ezberler.
Precision mı Recall mü?
Yanlış alarmın maliyeti yüksekse Precision (spam filtresi); kaçırmanın maliyeti yüksekse Recall (hastalık taraması).
Neden CAP'te Partition Tolerance'tan vazgeçemeyiz?
Gerçek ağlarda kesinti kaçınılmazdır; sistem bölünmeyi “yaşamamayı” seçemez. Bu yüzden gerçek seçim C ile A arasındadır.
TCP yerine UDP ne zaman?
Hız ve düşük gecikme, veri kaybından daha önemliyse: canlı yayın, online oyun, VoIP, DNS sorguları.
Neden Bubble Sort verimsiz?
Her turda yalnızca komşu karşılaştırmalarıyla ilerler; iç içe iki döngü O(n²) yapar. Büyük verilerde Merge/Quick Sort (O(n log n)) tercih edilir.
Neden BST'de arama O(log n)?
Her karşılaştırmada alt ağaçların yarısı elenir; dengeli ağacın yüksekliği \(\log n\)‘dir. Ağaç dengesizleşip tek kola uzarsa bu garanti kaybolur ve O(n)’e düşer.
Neden BST'yi inorder dolaşırız?
Sol-Kök-Sağ sırası, BST kuralının (sol < kök < sağ) doğrudan karşılığıdır; bu yüzden çıktı küçükten büyüğe sıralı gelir.
DFS mi BFS mi?
En kısa yol / en yakın seviye aranıyorsa BFS (bellek O(genişlik)); tüm yolları gezmek, döngü tespiti veya derin çözüm aranıyorsa DFS (bellek O(derinlik), recursion ile kolay yazılır).
Neden aⁿbⁿ regular değildir?
Sonlu otomatın belleği yoktur, yalnızca sonlu sayıda durumu vardır; n sınırsız olduğu için kaç a gördüğünü hatırlayamaz. Saymak için stack gerekir → context-free.
NFA, DFA'dan güçlü müdür?
Hayır. İkisi de tam olarak düzenli dilleri tanır; her NFA subset construction ile DFA’ya çevrilebilir. NFA yalnızca daha kompakt yazılır.
Neden regex ile HTML parse edilmez?
HTML iç içe (nested) yapıdadır → context-free. Regex ise yalnızca regular dilleri tanır; iç içe açılış-kapanışları saymak için stack gerekir.
Neden OSI 7 katman ama TCP/IP 4?
OSI teorik bir referans modeldir, katmanları ayrıntılı ayırır. TCP/IP çalışan protokollerden türetilmiş pratik bir modeldir ve OSI’nin 5-6-7’sini tek “Uygulama”, 1-2’sini tek “Ağ Erişimi” katmanında birleştirir.
BST'ye aynı sayı tekrar gelirse?
Klasik tanımda kural kesin eşitsizlik (sol < kök < sağ) olduğu için değer yok sayılır. Saklanması gerekiyorsa düğümde count tutulur; alternatif olarak eşitler tutarlı biçimde hep sağa konur — inorder yine sıralı çıkar ama ağaç dengesizleşebilir.
Neden two's complement kullanılır?
Toplama ve çıkarma aynı donanım devresiyle yapılır (çıkarma = negatifin toplanması), tek bir sıfır gösterimi vardır ve taşma davranışı tutarlıdır. İşaret biti + büyüklük gösteriminde +0/−0 ikiliği ve ayrı bir çıkarma devresi gerekirdi.
Neden n & (n-1) == 0 ikinin kuvvetini bulur?
\(2^k\)’nin ikilik gösteriminde tek bir 1 vardır (1000…); n-1 o biti söndürüp sağındaki tüm bitleri 1 yapar (0111…). Ortak 1 kalmadığı için AND sonucu 0’dır. Birden fazla 1 içeren sayılarda üst bitler ortak kalır ve sonuç 0 çıkmaz.
Neden K-map başlıkları Gray code (00, 01, 11, 10) sırasındadır?
Komşu hücreler arasında tek bit değişsin diye; komşu 1’ler gruplandığında değişen o değişken ifadeden elenir. Normal ikilik sırada iki bit birden değişebilir ve sadeleştirme mantığı bozulur.
RR'de quantum küçük/büyük olursa?
Küçük olursa: context switch yükü CPU zamanını yer, verim düşer. Büyük olursa: RR, FCFS’e döner ve etkileşimli işlerin tepki süresi bozulur.
Neden TCP kapanışı 4 adım (FIN/ACK ×2)?
Bağlantı çift yönlüdür ve her yön bağımsız kapatılır; bir taraf FIN gönderdikten sonra diğer tarafın hâlâ gönderecek verisi olabilir (half-close).
Neden TLS'te asimetrik + simetrik birlikte?
Asimetrik, güvenli anahtar paylaşımını çözer ama yavaştır; asıl veri, el sıkışmada üretilen hızlı simetrik oturum anahtarıyla şifrelenir.
Neden HTTP/3 UDP (QUIC) kullanır?
HTTP/2’de tek TCP bağlantısında bir paket kaybı tüm stream’leri bekletir (TCP head-of-line blocking). QUIC stream’leri bağımsız taşıyarak bunu çözer ve el sıkışmayı hızlandırır.
Neden NAND 'evrensel kapı'dır?
Yalnızca NAND’lerle NOT, AND, OR — dolayısıyla her devre — kurulabilir. Üretimde tek kapı tipiyle çalışmak basitlik ve maliyet avantajı sağlar. Aynısı NOR için de geçerlidir.
Bölüm 21 — Önerilen Çalışma Sırası
Konular birbirinin üzerine biniyor; bu sıra, önce temel sonra türev olacak şekilde kurulmuş hâli:
- 1. Veri yapıları + Algoritmalar (Big-O dâhil)
- 2. Sayı sistemleri + Bit işlemleri + Mantık kapıları + K-map (elle çevirme pratiği)
- 3. Otomata + Chomsky Hiyerarşisi (teorik temel)
- 4. OOP + SOLID + Design Patterns
- 5. SQL + Veritabanı + Normalizasyon + ACID/BASE/CAP
- 6. İşletim Sistemi + Process/Thread + Scheduling + Concurrency
- 7. Networking + OSI/TCP-IP + Subnetting + DNS/ARP + HTTP + REST
- 8. Testing + Git
- 9. System Design + Dağıtık sistemler (scaling, cache, queue)
- 10. Security (TLS dâhil)
- 11. AI/ML + RAG/LLM
- 12. Python kod örneklerini elle yazarak tekrar et (bit soruları dâhil)
Son madde en çok işe yarayanı oldu: kodu okumak yetmiyor, boş kâğıda elle yazmak gerekiyor. Aynı şey K-map ve subnetting için de geçerli — ikisi de “anladım” hissi verip sınavda elde patlayan konular.
Yorumlar