Prim Algoritması
Minimum kapsayan ağacı bir düğümden başlayıp her adımda en ucuz bağlantıyı ekleyerek büyüten algoritma.
Önce bunlara göz at
#Nasıl çalışır?
Prim algoritması da minimum kapsayan ağacı bulur ama Kruskal'dan farklı bir yol izler: kenarları tek tek sıralamak yerine ağacı bir başlangıç düğümünden büyütür.
Her adımda ağacın içindeki bir düğümü dışarıdaki bir düğüme bağlayan en ucuz kenar seçilir ve o düğüm ağaca katılır. Dışarıdaki her düğüm için "ağaca en ucuz bağlantı" (key) tutulur ve bir öncelik kuyruğuyla en küçüğü bulunur.
Yapısı Dijkstra'ya çok benzer; tek fark karşılaştırılan değerdir. Dijkstra başlangıca olan toplam mesafeye (dist[u] + w), Prim ise yalnızca kenarın ağırlığına (w) bakar. Başlangıç düğümü hangisi olursa olsun toplam ağırlık aynıdır.
#Kendin dene
Komşuluk listesi
- 1: 2 (4), 3 (1)
- 2: 1 (4), 4 (5), 5 (2)
- 3: 1 (1), 5 (2), 6 (4)
- 4: 2 (5), 7 (3)
- 5: 2 (2), 3 (2), 7 (6)
- 6: 3 (4), 7 (1)
- 7: 4 (3), 5 (6), 6 (1)
Prim ağacı tek bir düğümden büyütür: her adımda ağacı dışarıdaki bir düğüme bağlayan en ucuz kenarı ekler.
#Adım adım
- 01key[başlangıç] = 0, diğer tüm key değerleri ∞.
- 02Ağacın dışındaki düğümlerden key değeri en küçük olanı (u) seç ve ağaca ekle.
- 03u'nun dışarıdaki her komşusu v için kenar ağırlığı w < key[v] ise key[v] = w ve prev[v] = u yap.
- 04Tüm düğümler ağaca katılana kadar tekrarla; prev[] kenarları ağacı oluşturur.
#Örnek kod
Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.
import heapq
EDGES = [(1, 2, 4), (1, 3, 1), (2, 4, 5), (2, 5, 2), (3, 5, 2), (3, 6, 4), (4, 7, 3), (5, 7, 6), (6, 7, 1)]
graph = {v: [] for v in range(1, 8)}
for a, b, w in EDGES:
graph[a].append((b, w))
graph[b].append((a, w))
def prim(start: int):
in_tree, order, total = set(), [], 0
heap = [(0, start)] # (cheapest known link to the tree, node)
while heap:
w, u = heapq.heappop(heap)
if u in in_tree:
continue # an outdated, more expensive link
in_tree.add(u)
order.append(u)
total += w
for v, weight in graph[u]:
if v not in in_tree:
heapq.heappush(heap, (weight, v))
return order, total
order, total = prim(1)
print(" ".join(map(str, order))) # the order nodes joined the tree
print(total)#Karmaşıklık
| İşlem | Süre |
|---|---|
| İkili heap ile | O((V + E) log V) |
| Dizi ile (yoğun graf) | O(V²) |
| Fibonacci heap ile | O(E + V log V) |
| Bellek | O(V) |
Yoğun graflarda (E ≈ V²) heap'siz dizi sürümü O(V²) ile Kruskal'ın O(E log E) = O(V² log V) maliyetinden hızlıdır. Seyrek graflarda Kruskal genellikle daha basit ve hızlıdır. Graf bağlı değilse Prim yalnızca başlangıcın bulunduğu parçayı kapsar.
#Ne zaman kullanılır?
Yoğun graflarda MST (ör. her şehrin her şehre bağlanabildiği bir ağ), labirent üretimi (rastgele ağırlıklarla Prim güzel labirentler üretir) ve ağın bir merkezden büyüyerek kurulduğu durumlar Prim için uygundur.
#Alıştırma
Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.
Kolay
Prim her adımda hangi kenarı ekler?
- 1Ağaçtan dışarıdaki bir düğüme giden en ucuz kenarı
- 2Graftaki en hafif kenarı
- 3Başlangıca en yakın düğümün kenarını
- 4Rastgele bir kenarı
Prim ile Dijkstra arasındaki temel fark nedir?
- 1Prim kenar ağırlığını (w), Dijkstra toplam mesafeyi (dist[u] + w) karşılaştırır
- 2Prim negatif ağırlıkla çalışır
- 3Dijkstra kuyruk kullanmaz
- 4Hiçbir fark yoktur
Prim'i farklı bir başlangıç düğümünden çalıştırmak MST'nin toplam ağırlığını değiştirir mi?
- 1Hayır, toplam ağırlık hep aynıdır
- 2Evet, her zaman değişir
- 3Yalnızca yoğun graflarda değişir
- 4Yalnızca negatif ağırlıklarda değişir
Orta
key[v] = 6 iken ağaca yeni eklenen u'dan v'ye ağırlığı 4 olan bir kenar varsa ne olur?
- 1key[v] = 4 ve prev[v] = u olur
- 2key[v] = 10 olur
- 3v hemen ağaca eklenir
- 4Hiçbir şey değişmez
Zor
Hangi durumda Prim'in dizi (heap'siz) sürümü Kruskal'dan daha hızlıdır?
- 1Yoğun graflarda (E ≈ V²)
- 2Seyrek graflarda (E ≈ V)
- 3Kenarlar zaten sıralıyken
- 4Graf bağlı değilken