- Bir grafı komşuluk matrisi ya da komşuluk listeleriyle göstermek ve seçimi gerekçelendirmek
- BFS, DFS ve Dijkstra algoritmasını elle izlemek
- Topolojik sıra ve minimum kapsayan ağaç bulmak
Bir navigasyon uygulaması Bakü'den Şeki'ye en kısa yolu bir saniyede bulur, bir sosyal ağ “tanıyor olabileceğin kişileri” önerir, bir üniversite de dersleri kimse “Programlama”dan önce “Algoritmalar”a yazılmasın diye sıralar. Üç farklı problem, tek model: graf. Graf, nesneleri (köşeleri) ve aralarındaki bağlantıları (kenarları) tanımlar ve bilgisayar biliminin en çok kullanılan modellerinden biridir.
Graflar ve gösterimleri
Bir V köşeler kümesi ve bir E kenarlar (köşe çiftleri) kümesi. Kenarlar yönsüz (arkadaşlık) ya da yönlü (A → B, “takip ediyor”) olabilir; her kenarın bir ağırlığı (uzaklık, maliyet, süre) varsa graf ağırlıklıdır. Bir köşenin derecesi, ona değen kenarların sayısıdır.
- deg(v)v köşesinin derecesi
- |V|, |E|köşe ve kenar sayıları
“El sıkışma önermesi”: her yönsüz kenar derece toplamına iki uçta birer olmak üzere 2 ekler. İkinci eşitsizlik, basit yönsüz bir grafta en fazla kenar sayısıdır.
| Özellik | Komşuluk matrisi | Komşuluk listeleri |
|---|---|---|
| bellek | O(V²) | O(V + E) |
| (u, v) kenarı var mı? | O(1) | O(deg u) |
| u'nun tüm komşularını gezmek | O(V) | O(deg u) |
| ne zaman seçilir | yoğun graf (E ≈ V²) | seyrek graf (yollar, sosyal ağlar) |
Ders boyunca tek bir örnek graf kullanacağız. Altı köşe A–F ve ağırlıklı yönsüz kenarlar: A–B 4, A–C 2, B–C 1, B–D 5, C–D 8, C–E 10, D–E 2, D–F 6, E–F 3. Ağırlıkları kilometre olarak düşün.
Genişlik öncelikli (BFS) ve derinlik öncelikli (DFS) arama
BFS başlangıç köşesinden bir dalga gibi yayılır: önce tüm komşular, sonra komşuların komşuları. Bir kuyruk kullanır ve ağırlıksız bir grafta kenar sayısı bakımından en kısa yolları verir. DFS ise bir yol boyunca olabildiğince derine iner, çıkmaza gelince geri döner; yığıtla (ya da özyinelemeyle) çalışır ve bağlılık, döngü bulma ve topolojik sıralama için kullanılır. İkisi de her köşeye ve her kenara bir kez bakar: O(V + E).
Ağırlıkları dikkate almadan örnek grafta F'den BFS ve DFS uygula. Komşuları alfabetik sırayla al: A: B, C; B: A, C, D; C: A, B, D, E; D: B, C, E, F; E: C, D, F; F: D, E.
Çözümü gösterÇözümü gizle
Düzeyler: F | D, E | B, C | A.
DFS (özyineleme): F → D (F'nin ilk komşusu) → B (D'nin ilk ziyaret edilmemiş komşusu) → A → C (A'nın komşusu) → E (C'nin ziyaret edilmemiş komşusu).
Sıra: F, D, B, A, C, E; DFS A'ya 4 adımda ulaştı, BFS ise en kısa yolu (3 kenar) buldu.
from collections import deque
graph = {'A': ['B', 'C'], 'B': ['A', 'C', 'D'], 'C': ['A', 'B', 'D', 'E'],
'D': ['B', 'C', 'E', 'F'], 'E': ['C', 'D', 'F'], 'F': ['D', 'E']}
def bfs(start):
dist = {start: 0}
queue = deque([start])
while queue:
v = queue.popleft()
for w in graph[v]:
if w not in dist:
dist[w] = dist[v] + 1
queue.append(w)
return dist
def dfs(v, seen):
seen.append(v)
for w in graph[v]:
if w not in seen:
dfs(w, seen)
return seen
print('BFS from F:', bfs('F'))
print('DFS from F:', dfs('F', []))▸ Beklenen çıktı
BFS from F: {'F': 0, 'D': 1, 'E': 1, 'B': 2, 'C': 2, 'A': 3}
DFS from F: ['F', 'D', 'B', 'A', 'C', 'E']Dijkstra algoritması: ağırlıklı en kısa yollar
Kenarların ağırlığı olunca BFS işe yaramaz: üç kısa kenar tek bir uzun kenardan ucuz olabilir. Dijkstra algoritması (negatif olmayan ağırlıklar için) her adımda henüz kesinleşmemiş köşeler arasından uzaklığı en küçük olanı seçer (öncelik kuyruğu), onu kesinleştirir ve komşularının uzaklıklarını gevşetme (relaxation) ile günceller.
- dist[v]kaynaktan v'ye şimdiye kadar bulunan en kısa uzaklık
- w(u, v)u–v kenarının ağırlığı (≥ 0)
- Tikili yığınla çalışma süresi
| Adım: kesinleşen | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| 0: başlangıç | 0 | ∞ | ∞ | ∞ | ∞ | ∞ |
| 1: A (0) | 0 | 4 | 2 | ∞ | ∞ | ∞ |
| 2: C (2) | 0 | 3 | 2 | 10 | 12 | ∞ |
| 3: B (3) | 0 | 3 | 2 | 8 | 12 | ∞ |
| 4: D (8) | 0 | 3 | 2 | 8 | 10 | 14 |
| 5: E (10) | 0 | 3 | 2 | 8 | 10 | 13 |
| 6: F (13) | 0 | 3 | 2 | 8 | 10 | 13 |
Tabloyu kullanarak A'dan F'ye en kısa yolu ve uzunluğunu bul.
Çözümü gösterÇözümü gizle
Sondan geriye: F ← E ← D ← B ← C ← A.
Yol: A → C → B → D → E → F, uzunluk 2 + 1 + 5 + 2 + 3 = 13.
Dikkat: ilk bakışta akla gelen A → B → D → F yolu 4 + 5 + 6 = 15'tir.
import heapq
edges = [('A', 'B', 4), ('A', 'C', 2), ('B', 'C', 1), ('B', 'D', 5), ('C', 'D', 8),
('C', 'E', 10), ('D', 'E', 2), ('D', 'F', 6), ('E', 'F', 3)]
adj = {}
for u, v, w in edges:
adj.setdefault(u, []).append((v, w))
adj.setdefault(v, []).append((u, w))
def dijkstra(src):
dist, prev, pq = {src: 0}, {}, [(0, src)]
while pq:
d, u = heapq.heappop(pq)
if d > dist[u]:
continue
for v, w in adj[u]:
if d + w < dist.get(v, float('inf')):
dist[v], prev[v] = d + w, u
heapq.heappush(pq, (d + w, v))
return dist, prev
dist, prev = dijkstra('A')
path = ['F']
while path[-1] != 'A':
path.append(prev[path[-1]])
print(dict(sorted(dist.items())))
print(' -> '.join(reversed(path)), '=', dist['F'])▸ Beklenen çıktı
{'A': 0, 'B': 3, 'C': 2, 'D': 8, 'E': 10, 'F': 13}
A -> C -> B -> D -> E -> F = 13heapq üstlenir. Bir köşe kuyruğa birkaç kez girebilir; eskimiş kayıtları d > dist[u] koşulu atlar (“tembel silme”).Topolojik sıralama ve minimum kapsayan ağaç
Topolojik sıralama, yönlü döngüsüz bir grafın (DAG) köşelerini her u → v kenarı için u, v'den önce gelecek biçimde dizer: ders önkoşulları, program modüllerinin derlenme sırası, Excel'de hücrelerin yeniden hesaplanma sırası. Kahn algoritması: iç derecesi 0 olan köşeleri kuyruğa koy, birini çıkar, kenarlarını sil ve iç derecesi 0'a düşen köşeleri kuyruğa ekle. V'den az köşe çıkarsa grafta döngü vardır. Süre: O(V + E).
from collections import deque
courses = {'Programming': ['DataStructures', 'Databases'], 'Math': ['Algorithms'],
'DataStructures': ['Algorithms'], 'Databases': ['AI'],
'Algorithms': ['AI'], 'AI': []}
def topo_sort(g):
indeg = {v: 0 for v in g}
for v in g:
for w in g[v]:
indeg[w] += 1
queue = deque(v for v in g if indeg[v] == 0)
order = []
while queue:
v = queue.popleft()
order.append(v)
for w in g[v]:
indeg[w] -= 1
if indeg[w] == 0:
queue.append(w)
return order if len(order) == len(g) else None
print(topo_sort(courses))
print(topo_sort({'X': ['Y'], 'Y': ['Z'], 'Z': ['X']}))▸ Beklenen çıktı
['Programming', 'Math', 'DataStructures', 'Databases', 'Algorithms', 'AI'] None
None döner: böyle önkoşullarla hiçbir derse başlanamaz.Bağlı ağırlıklı bir grafın tüm köşelerini birleştiren, döngü içermeyen ve toplam ağırlığı olabilecek en küçük olan kenar kümesi. Her zaman tam V − 1 kenarı vardır. Kullanımlar: köyleri en az kabloyla bağlamak, elektrik ve su şebekesi tasarımı, kümeleme.
Örnek grafın minimum kapsayan ağacını Kruskal algoritmasıyla bul: kenarları artan ağırlıkla al ve döngü oluşturmayanları seç.
Çözümü gösterÇözümü gizle
B–C 1 ✓ → {B, C}
A–C 2 ✓ → {A, B, C}
D–E 2 ✓ → {D, E}
E–F 3 ✓ → {D, E, F}
A–B 4 ✗ — A ve B zaten aynı bileşende (A–C–B döngüsü kapanırdı)
B–D 5 ✓ → tüm köşeler birleşti; 5 = V − 1 kenar, dur.
MST: {B–C, A–C, D–E, E–F, B–D}, toplam ağırlık 1 + 2 + 2 + 3 + 5 = 13.
edges = [('A', 'B', 4), ('A', 'C', 2), ('B', 'C', 1), ('B', 'D', 5), ('C', 'D', 8),
('C', 'E', 10), ('D', 'E', 2), ('D', 'F', 6), ('E', 'F', 3)]
parent = {v: v for v in 'ABCDEF'}
def find(v):
while parent[v] != v:
v = parent[v]
return v
mst = []
for u, v, w in sorted(edges, key=lambda e: e[2]):
ru, rv = find(u), find(v)
if ru != rv:
parent[ru] = rv
mst.append((u, v, w))
print(mst)
print('total weight:', sum(w for _, _, w in mst))▸ Beklenen çıktı
[('B', 'C', 1), ('A', 'C', 2), ('D', 'E', 2), ('E', 'F', 3), ('B', 'D', 5)]
total weight: 13find bir bileşenin “temsilcisini” bulur; iki köşenin temsilcisi aynıysa kenar bir döngü kapatır. Kruskal'ın süresini sıralama belirler: O(E log E). Prim algoritması ise ağacı bir köşeden büyütür (Dijkstra'ya benzer, öncelik kuyruğuyla).Önemli noktalar
- Graf G = (V, E)'dir; seyrek graflar için komşuluk listesi (O(V + E)), yoğun graflar için matris (O(V²)).
- BFS kuyrukla düzey düzey ilerler ve ağırlıksız en kısa yolları verir; DFS yığıtla derine iner; ikisi de O(V + E)'dir.
- Dijkstra negatif olmayan ağırlıklarla, öncelik kuyruğu ve gevşetmeyle O((V + E) log V) sürede çalışır.
- Topolojik sıra yalnızca DAG'de vardır; Kahn algoritması döngüleri de saptar.
- MST'nin V − 1 kenarı vardır; Kruskal kenarları ağırlığa göre sıralar ve union–find ile döngülerden kaçınır.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.