🌍 10.7: Graf Örnekleri

Gerçek Dünya Problemlerini Graflarla Çözmek

📌 Graflar Nerede Kullanılır?

Graflar, günlük hayatımızda farkında olmadan sürekli kullandığımız sistemlerin temelini oluşturur. Google Maps'te yol tarifi aldığınızda, Facebook'ta arkadaş önerisi gördüğünüzde, Netflix'te "Bunları da beğenebilirsiniz" önerisi aldığınızda arka planda graf algoritmaları çalışmaktadır.

🗺️ Navigasyon & Haritalar

Google Maps, Waze, Yandex: Şehirler düğüm, yollar kenar. Dijkstra ve A* algoritmaları ile en kısa/hızlı rota bulunur. Trafik bilgisi kenar ağırlıklarını dinamik günceller.

👥 Sosyal Ağlar

Facebook, LinkedIn, Twitter: Kişiler düğüm, arkadaşlıklar kenar. "Ortak arkadaş" önerileri BFS ile, topluluk tespiti clustering algoritmaları ile yapılır.

🌐 Web & Arama Motorları

Google PageRank: Web sayfaları düğüm, linkler yönlü kenar. Bir sayfaya gelen link sayısı ve kalitesi "önem" skorunu belirler.

📦 Lojistik & Tedarik Zinciri

Amazon, UPS, FedEx: Depolar ve müşteriler düğüm, teslimat rotaları kenar. TSP ve VRP (Vehicle Routing Problem) algoritmaları kullanılır.

🧬 Biyoinformatik

DNA Sequencing: k-mer parçaları düğüm, örtüşmeler kenar. Euler yolu ile genom assembly yapılır. Protein etkileşim ağları hastalık araştırmalarında kritik.

💼 Proje Yönetimi

PERT/CPM: Görevler düğüm, bağımlılıklar kenar. Topological sort ile görev sırası, kritik yol analizi ile proje süresi hesaplanır.

🎮 Oyun Geliştirme

NPC Pathfinding: Harita grid düğüm, hareket yönleri kenar. A* algoritması ile düşmanlar/karakterler hedefe en kısa yoldan gider.

🔌 Elektrik & Telekomünikasyon

Şebeke Tasarımı: MST algoritmaları ile minimum kablo kullanarak tüm bölgeleri birbirine bağlama. Fiber optik ağ planlaması.

🤖 Yapay Zeka & ML

Knowledge Graphs: Google, Amazon, Netflix öneri sistemleri. Kavramlar düğüm, ilişkiler kenar. GNN (Graph Neural Networks) ile öğrenme.

🔒 Siber Güvenlik

Ağ Analizi: Bilgisayarlar düğüm, bağlantılar kenar. Anormal trafik kalıpları, botnet tespiti, saldırı yayılım analizi.

✈️ Havacılık

Uçuş Ağları: Havalimanları düğüm, uçuş rotaları kenar. Hub optimizasyonu, gecikme yayılım analizi, kapasite planlaması.

📱 İletişim Ağları

5G/Internet: Router'lar düğüm, bağlantılar kenar. Paket yönlendirme, yük dengeleme, network topology optimization.

💡 Önemli Kavram: Gerçek Dünya → Graf Modeli

Her graf probleminde şu adımları izleyin:

  1. Düğümler ne? - Şehirler, insanlar, web sayfaları, görevler...
  2. Kenarlar ne? - Yollar, arkadaşlıklar, linkler, bağımlılıklar...
  3. Yönlü mü? - Twitter takip (yönlü) vs Facebook arkadaşlık (yönsüz)
  4. Ağırlıklı mı? - Mesafe, süre, maliyet varsa ağırlıklı
  5. Hangi problemi çözüyorum? - En kısa yol, bağlantı, döngü, MST...
👥

Örnek 1: Sosyal Ağ Analizi

Arkadaş önerisi ve topluluk tespiti

📋 Senaryo

Bir sosyal medya platformundasınız. Kullanıcılara yeni arkadaş önerileri yapmak ve toplulukları (grupları) tespit etmek istiyorsunuz.

Sosyal Ağ - Arkadaş Önerisi
from collections import defaultdict

class SocialNetwork:
    """Sosyal ağ graf modeli"""
    
    def __init__(self):
        self.friendships = defaultdict(set)
    
    def add_friendship(self, person1, person2):
        """Çift yönlü arkadaşlık ekle"""
        self.friendships[person1].add(person2)
        self.friendships[person2].add(person1)
    
    def get_friends(self, person):
        """Direkt arkadaşları getir"""
        return self.friendships[person]
    
    def suggest_friends(self, person, limit=3):
        """
        Arkadaş önerisi - 'Ortak arkadaş' yöntemi
        
        Mantık: Seni tanımayan ama seninle ortak arkadaşları olan kişiler
        iyi arkadaş adaylarıdır!
        """
        direct_friends = self.get_friends(person)
        suggestions = defaultdict(int)  # {önerilen: ortak arkadaş sayısı}
        
        # Her arkadaşın arkadaşlarına bak
        for friend in direct_friends:
            for friend_of_friend in self.get_friends(friend):
                # Kendisi veya zaten arkadaş değilse
                if friend_of_friend != person and friend_of_friend not in direct_friends:
                    suggestions[friend_of_friend] += 1
        
        # Ortak arkadaş sayısına göre sırala
        sorted_suggestions = sorted(
            suggestions.items(), 
            key=lambda x: x[1], 
            reverse=True
        )
        
        return sorted_suggestions[:limit]
    
    def mutual_friends(self, person1, person2):
        """İki kişinin ortak arkadaşları"""
        friends1 = self.get_friends(person1)
        friends2 = self.get_friends(person2)
        return friends1.intersection(friends2)


# Sosyal ağ oluştur
network = SocialNetwork()

# Arkadaşlıklar
friendships = [
    ('Ali', 'Veli'), ('Ali', 'Ayşe'), ('Ali', 'Fatma'),
    ('Veli', 'Mehmet'), ('Veli', 'Ayşe'),
    ('Ayşe', 'Zeynep'), ('Ayşe', 'Can'),
    ('Fatma', 'Zeynep'), ('Fatma', 'Deniz'),
    ('Mehmet', 'Can'), ('Zeynep', 'Can')
]

for p1, p2 in friendships:
    network.add_friendship(p1, p2)

print("=== SOSYAL AĞ ANALİZİ ===\n")
print("Arkadaşlık ağı:")
for person in sorted(network.friendships.keys()):
    friends = sorted(network.friendships[person])
    print(f"  {person}: {friends}")

print("\n=== ALİ İÇİN ARKADAŞ ÖNERİLERİ ===")
suggestions = network.suggest_friends('Ali')
for suggested, mutual_count in suggestions:
    print(f"  {suggested} ({mutual_count} ortak arkadaş)")

print("\n=== ORTAK ARKADAŞLAR ===")
print(f"Ali & Mehmet: {network.mutual_friends('Ali', 'Mehmet')}")
print(f"Ali & Can: {network.mutual_friends('Ali', 'Can')}")
Çıktı bekleniyor...
Sosyal Ağ - Topluluk Tespiti
from collections import deque, defaultdict

def find_communities(friendships_list):
    """
    Bağlantılı bileşenler = Topluluklar
    
    Her bağlantılı grup ayrı bir topluluk olarak kabul edilir.
    """
    # Graf oluştur
    graph = defaultdict(set)
    for p1, p2 in friendships_list:
        graph[p1].add(p2)
        graph[p2].add(p1)
    
    visited = set()
    communities = []
    
    for person in graph:
        if person not in visited:
            # Yeni topluluk bulduk - BFS ile keşfet
            community = []
            queue = deque([person])
            
            while queue:
                current = queue.popleft()
                if current in visited:
                    continue
                
                visited.add(current)
                community.append(current)
                
                for friend in graph[current]:
                    if friend not in visited:
                        queue.append(friend)
            
            communities.append(sorted(community))
    
    return communities


def find_influencers(friendships_list, top_n=3):
    """
    Etki sahibi kişileri bul - Derece (arkadaş sayısı) analizi
    
    Daha gelişmiş: PageRank, Betweenness Centrality
    """
    degree = defaultdict(int)
    
    for p1, p2 in friendships_list:
        degree[p1] += 1
        degree[p2] += 1
    
    sorted_by_degree = sorted(
        degree.items(),
        key=lambda x: x[1],
        reverse=True
    )
    
    return sorted_by_degree[:top_n]


# Test verileri - iki ayrı topluluk
friendships = [
    # Topluluk 1: Üniversite arkadaşları
    ('Ali', 'Veli'), ('Ali', 'Ayşe'), ('Veli', 'Ayşe'),
    ('Ayşe', 'Fatma'), ('Fatma', 'Veli'),
    
    # Topluluk 2: İş arkadaşları
    ('Can', 'Deniz'), ('Can', 'Elif'),
    ('Deniz', 'Elif'), ('Elif', 'Gül'),
    
    # Topluluk 3: Aile
    ('Hasan', 'Hüseyin')
]

print("=== TOPLULUK TESPİTİ ===\n")
communities = find_communities(friendships)

for i, community in enumerate(communities, 1):
    print(f"Topluluk {i}: {community}")

print(f"\n📊 Toplam {len(communities)} topluluk bulundu")

print("\n=== EN ETKİLİ KİŞİLER (Derece Analizi) ===")
influencers = find_influencers(friendships)
for person, degree in influencers:
    print(f"  {person}: {degree} bağlantı")
Çıktı bekleniyor...
🗺️

Örnek 2: Navigasyon Sistemi

En kısa yol ve alternatif rotalar

📋 Senaryo

Bir şehir içi navigasyon sistemi geliştiriyorsunuz. Kullanıcıya en kısa yolu ve alternatif rotaları göstermeniz gerekiyor.

Şehir Navigasyonu - Dijkstra
import heapq
from collections import defaultdict

class CityNavigation:
    """Şehir navigasyon sistemi"""
    
    def __init__(self):
        # {location: [(neighbor, distance, road_name), ...]}
        self.roads = defaultdict(list)
    
    def add_road(self, loc1, loc2, distance, road_name=""):
        """Çift yönlü yol ekle"""
        self.roads[loc1].append((loc2, distance, road_name))
        self.roads[loc2].append((loc1, distance, road_name))
    
    def find_shortest_path(self, start, end):
        """Dijkstra ile en kısa yol"""
        if start not in self.roads or end not in self.roads:
            return None, float('inf'), []
        
        distances = {loc: float('inf') for loc in self.roads}
        distances[start] = 0
        previous = {loc: (None, "") for loc in self.roads}
        
        pq = [(0, start)]
        visited = set()
        
        while pq:
            dist, current = heapq.heappop(pq)
            
            if current in visited:
                continue
            visited.add(current)
            
            if current == end:
                break
            
            for neighbor, road_dist, road_name in self.roads[current]:
                if neighbor not in visited:
                    new_dist = dist + road_dist
                    if new_dist < distances[neighbor]:
                        distances[neighbor] = new_dist
                        previous[neighbor] = (current, road_name)
                        heapq.heappush(pq, (new_dist, neighbor))
        
        # Yolu oluştur
        path = []
        roads_taken = []
        current = end
        
        while current is not None:
            path.append(current)
            prev_loc, road_name = previous[current]
            if road_name:
                roads_taken.append(road_name)
            current = prev_loc
        
        path.reverse()
        roads_taken.reverse()
        
        return path, distances[end], roads_taken
    
    def print_directions(self, start, end):
        """Yol tarifi yazdır"""
        path, distance, roads = self.find_shortest_path(start, end)
        
        if distance == float('inf'):
            print(f"❌ {start} → {end} arası yol bulunamadı!")
            return
        
        print(f"\n🗺️ YOL TARİFİ: {start} → {end}")
        print(f"📏 Toplam mesafe: {distance} km\n")
        
        for i in range(len(path) - 1):
            from_loc = path[i]
            to_loc = path[i + 1]
            road = roads[i] if i < len(roads) else ""
            print(f"  {i+1}. {from_loc} → {to_loc} ({road})")
        
        print(f"\n✅ Varış: {end}")


# İstanbul haritası (basitleştirilmiş)
nav = CityNavigation()

# Ana yollar
nav.add_road('Kadıköy', 'Üsküdar', 8, 'Sahil Yolu')
nav.add_road('Üsküdar', 'Beşiktaş', 5, 'Boğaz Köprüsü')
nav.add_road('Beşiktaş', 'Taksim', 3, 'İnönü Caddesi')
nav.add_road('Taksim', 'Şişli', 4, 'Halaskargazi Caddesi')
nav.add_road('Kadıköy', 'Maltepe', 10, 'E5')
nav.add_road('Maltepe', 'Kartal', 6, 'E5')
nav.add_road('Beşiktaş', 'Şişli', 5, 'Barbaros Bulvarı')
nav.add_road('Şişli', 'Mecidiyeköy', 2, 'Büyükdere Caddesi')
nav.add_road('Taksim', 'Beyoğlu', 1, 'İstiklal Caddesi')
nav.add_road('Üsküdar', 'Kadıköy', 8, 'Sahil Yolu')

print("=== İSTANBUL NAVİGASYON ===")
nav.print_directions('Kadıköy', 'Taksim')
nav.print_directions('Maltepe', 'Mecidiyeköy')
Çıktı bekleniyor...
📦

Örnek 3: Görev Planlama (Task Scheduling)

Topological sort ile bağımlılık çözme

📋 Senaryo

Bir yazılım projesinde görevler arasında bağımlılıklar var. Görevleri hangi sırayla yapmanız gerektiğini belirleyin.

Proje Yönetimi - Topological Sort
from collections import defaultdict, deque

class ProjectScheduler:
    """Görev planlama sistemi - DAG tabanlı"""
    
    def __init__(self):
        self.tasks = {}  # {task: {'duration': int, 'deps': []}}
        self.graph = defaultdict(list)  # Bağımlılık grafı
    
    def add_task(self, name, duration, dependencies=None):
        """Görev ekle"""
        deps = dependencies or []
        self.tasks[name] = {'duration': duration, 'deps': deps}
        
        # Graf kenarları: bağımlılık → görev
        for dep in deps:
            self.graph[dep].append(name)
        
        # Bağımlılığı olmayan görevleri de grafta tut
        if name not in self.graph:
            self.graph[name] = []
    
    def topological_sort(self):
        """Kahn algoritması ile topological sort"""
        # In-degree hesapla
        in_degree = defaultdict(int)
        for task in self.tasks:
            in_degree[task] = len(self.tasks[task]['deps'])
        
        # In-degree 0 olan görevlerle başla
        queue = deque([t for t in self.tasks if in_degree[t] == 0])
        result = []
        
        while queue:
            task = queue.popleft()
            result.append(task)
            
            # Bu göreve bağlı olanların in-degree'sini azalt
            for dependent in self.graph[task]:
                in_degree[dependent] -= 1
                if in_degree[dependent] == 0:
                    queue.append(dependent)
        
        # Döngü kontrolü
        if len(result) != len(self.tasks):
            return None  # Döngü var!
        
        return result
    
    def has_cycle(self):
        """Döngü var mı?"""
        return self.topological_sort() is None
    
    def calculate_critical_path(self):
        """Kritik yol ve minimum proje süresi"""
        order = self.topological_sort()
        if order is None:
            return None, None
        
        # En erken başlama zamanları
        earliest_start = {task: 0 for task in self.tasks}
        
        for task in order:
            for dep in self.tasks[task]['deps']:
                dep_end = earliest_start[dep] + self.tasks[dep]['duration']
                earliest_start[task] = max(earliest_start[task], dep_end)
        
        # En son biten görev = proje süresi
        project_duration = max(
            earliest_start[t] + self.tasks[t]['duration'] 
            for t in self.tasks
        )
        
        return order, project_duration
    
    def print_schedule(self):
        """Zamanlama çizelgesi"""
        order, duration = self.calculate_critical_path()
        
        if order is None:
            print("❌ Döngüsel bağımlılık! Planlama yapılamaz.")
            return
        
        print("=== PROJE PLANI ===\n")
        print("Görev Sırası:")
        
        # En erken başlama zamanları
        earliest_start = {task: 0 for task in self.tasks}
        for task in order:
            for dep in self.tasks[task]['deps']:
                dep_end = earliest_start[dep] + self.tasks[dep]['duration']
                earliest_start[task] = max(earliest_start[task], dep_end)
        
        for i, task in enumerate(order, 1):
            info = self.tasks[task]
            deps_str = ', '.join(info['deps']) if info['deps'] else '-'
            start = earliest_start[task]
            end = start + info['duration']
            print(f"  {i}. {task}")
            print(f"     Süre: {info['duration']} gün | Başlangıç: Gün {start} | Bitiş: Gün {end}")
            print(f"     Bağımlılıklar: {deps_str}")
            print()
        
        print(f"📅 Toplam proje süresi: {duration} gün")


# Yazılım projesi örneği
project = ProjectScheduler()

# Görevler ve bağımlılıkları
project.add_task('Gereksinim Analizi', 5)
project.add_task('Veritabanı Tasarımı', 3, ['Gereksinim Analizi'])
project.add_task('API Tasarımı', 4, ['Gereksinim Analizi'])
project.add_task('Frontend Tasarımı', 3, ['Gereksinim Analizi'])
project.add_task('Backend Geliştirme', 10, ['Veritabanı Tasarımı', 'API Tasarımı'])
project.add_task('Frontend Geliştirme', 8, ['Frontend Tasarımı', 'API Tasarımı'])
project.add_task('Entegrasyon', 4, ['Backend Geliştirme', 'Frontend Geliştirme'])
project.add_task('Test', 5, ['Entegrasyon'])
project.add_task('Deploy', 2, ['Test'])

project.print_schedule()
Çıktı bekleniyor...
🌐

Örnek 4: Web Crawler

BFS ile web sayfalarını tarama

📋 Senaryo

Bir arama motoru geliştiriyorsunuz. Web sayfalarını BFS ile tarayarak sayfa bağlantılarını keşfetmeniz gerekiyor.

Web Crawler Simülasyonu
from collections import deque, defaultdict

class WebCrawler:
    """
    BFS tabanlı Web Crawler simülasyonu
    
    Gerçek dünyada: requests + BeautifulSoup kullanılır
    """
    
    def __init__(self):
        # Simüle edilmiş web sayfaları
        self.web = {
            'ana-sayfa': ['hakkimizda', 'urunler', 'blog'],
            'hakkimizda': ['ana-sayfa', 'iletisim', 'ekip'],
            'urunler': ['ana-sayfa', 'urun-1', 'urun-2', 'urun-3'],
            'blog': ['ana-sayfa', 'yazi-1', 'yazi-2'],
            'iletisim': ['ana-sayfa', 'hakkimizda'],
            'ekip': ['hakkimizda', 'iletisim'],
            'urun-1': ['urunler', 'urun-2'],
            'urun-2': ['urunler', 'urun-1', 'urun-3'],
            'urun-3': ['urunler'],
            'yazi-1': ['blog', 'yazi-2'],
            'yazi-2': ['blog', 'yazi-1']
        }
    
    def crawl_bfs(self, start_url, max_pages=10):
        """BFS ile sayfaları tara"""
        visited = set()
        queue = deque([(start_url, 0)])  # (url, derinlik)
        crawled = []
        
        while queue and len(crawled) < max_pages:
            url, depth = queue.popleft()
            
            if url in visited:
                continue
            
            # "Sayfayı indir" (simülasyon)
            if url in self.web:
                visited.add(url)
                crawled.append({'url': url, 'depth': depth})
                
                # Linkleri keşfet
                for link in self.web[url]:
                    if link not in visited:
                        queue.append((link, depth + 1))
        
        return crawled
    
    def build_link_graph(self):
        """Link grafı oluştur"""
        return dict(self.web)
    
    def calculate_pagerank(self, iterations=10, damping=0.85):
        """
        Basitleştirilmiş PageRank algoritması
        
        Her sayfanın "önemini" hesaplar.
        """
        pages = list(self.web.keys())
        n = len(pages)
        
        # Başlangıç: eşit değerler
        pagerank = {page: 1.0 / n for page in pages}
        
        for _ in range(iterations):
            new_pr = {}
            
            for page in pages:
                # Bu sayfaya link veren sayfalar
                incoming = [p for p in pages if page in self.web.get(p, [])]
                
                rank_sum = 0
                for inc_page in incoming:
                    # Gelen sayfanın rankını, link sayısına böl
                    outgoing_links = len(self.web.get(inc_page, []))
                    if outgoing_links > 0:
                        rank_sum += pagerank[inc_page] / outgoing_links
                
                new_pr[page] = (1 - damping) / n + damping * rank_sum
            
            pagerank = new_pr
        
        return pagerank


# Test
crawler = WebCrawler()

print("=== WEB CRAWLER ===\n")
print("Başlangıç: ana-sayfa")
print("Max sayfa: 10\n")

results = crawler.crawl_bfs('ana-sayfa', max_pages=10)

print("Taranan sayfalar:")
for page in results:
    indent = "  " * page['depth']
    print(f"{indent}📄 {page['url']} (derinlik: {page['depth']})")

print(f"\n✅ Toplam {len(results)} sayfa tarandı")

print("\n=== PAGERANK ANALİZİ ===\n")
pagerank = crawler.calculate_pagerank()

# Sırala ve yazdır
sorted_pr = sorted(pagerank.items(), key=lambda x: x[1], reverse=True)
for page, rank in sorted_pr[:5]:
    bar = "█" * int(rank * 100)
    print(f"  {page:15} {rank:.4f} {bar}")
Çıktı bekleniyor...
🧩

Örnek 5: Labirent Çözme

BFS ve DFS ile yol bulma

Labirent - BFS ile En Kısa Yol
from collections import deque

def solve_maze(maze, start, end):
    """
    BFS ile labirent çöz
    
    maze: 2D grid (0=yol, 1=duvar)
    start: (row, col) başlangıç
    end: (row, col) hedef
    
    Returns: En kısa yol veya None
    """
    rows, cols = len(maze), len(maze[0])
    
    # 4 yön: yukarı, aşağı, sol, sağ
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    
    visited = set()
    queue = deque([(start, [start])])  # ((row, col), path)
    
    while queue:
        (row, col), path = queue.popleft()
        
        # Hedefe ulaştık mı?
        if (row, col) == end:
            return path
        
        if (row, col) in visited:
            continue
        visited.add((row, col))
        
        # 4 yöne bak
        for dr, dc in directions:
            new_row, new_col = row + dr, col + dc
            
            # Sınırlar içinde mi?
            if 0 <= new_row < rows and 0 <= new_col < cols:
                # Duvar değil ve ziyaret edilmemiş mi?
                if maze[new_row][new_col] == 0 and (new_row, new_col) not in visited:
                    queue.append(((new_row, new_col), path + [(new_row, new_col)]))
    
    return None  # Yol bulunamadı


def print_maze_solution(maze, path):
    """Labirenti ve çözümü yazdır"""
    rows, cols = len(maze), len(maze[0])
    path_set = set(path) if path else set()
    
    # Semboller: █=duvar, ·=yol, ★=çözüm, S=başlangıç, E=bitiş
    for r in range(rows):
        row_str = ""
        for c in range(cols):
            if (r, c) == path[0] if path else False:
                row_str += "🟢"  # Başlangıç
            elif (r, c) == path[-1] if path else False:
                row_str += "🔴"  # Bitiş
            elif (r, c) in path_set:
                row_str += "🟨"  # Çözüm yolu
            elif maze[r][c] == 1:
                row_str += "⬛"  # Duvar
            else:
                row_str += "⬜"  # Boş yol
        print(row_str)


# Örnek labirent
maze = [
    [0, 0, 1, 0, 0, 0],
    [1, 0, 1, 0, 1, 0],
    [0, 0, 0, 0, 1, 0],
    [0, 1, 1, 1, 1, 0],
    [0, 0, 0, 0, 0, 0],
    [1, 1, 1, 1, 1, 0]
]

start = (0, 0)
end = (5, 5)

print("=== LABİRENT ÇÖZME ===\n")
print("Orijinal labirent (⬛=duvar, ⬜=yol):")
for row in maze:
    print("".join("⬛" if cell == 1 else "⬜" for cell in row))

print("\nBaşlangıç:", start)
print("Hedef:", end)

path = solve_maze(maze, start, end)

if path:
    print(f"\n✅ Çözüm bulundu! ({len(path)} adım)")
    print("\nÇözüm (🟢=başlangıç, 🔴=bitiş, 🟨=yol):")
    print_maze_solution(maze, path)
    print("\nYol:", " → ".join(str(p) for p in path))
else:
    print("\n❌ Çözüm bulunamadı!")
Çıktı bekleniyor...

🌲 Minimum Yayılan Ağaç (MST)

📚 MST Nedir?

Minimum Spanning Tree (MST), bir grafın tüm düğümlerini birbirine bağlayan, toplam kenar ağırlığı en düşük olan ağaç yapısıdır.

  • N düğümlü grafta MST, tam olarak N-1 kenar içerir
  • MST'de döngü yoktur
  • Tüm düğümler birbirine bağlıdır (connected)

🔌 Elektrik Şebekesi

Şehirleri minimum kablo ile bağlama

🌐 Ağ Tasarımı

Bilgisayar ağlarını minimum maliyetle kurma

🛤️ Yol Yapımı

Köyleri birbirine bağlayan en ucuz yol ağı

📡 Telekomünikasyon

Fiber optik kablo döşeme optimizasyonu

🎮 İnteraktif MST Görselleştirmesi

Kruskal ve Prim algoritmalarının adım adım çalışmasını izleyin:

📊 MST Bilgisi: Algoritmayı başlatın...
Kruskal Algoritması - Union-Find ile
class UnionFind:
    """Disjoint Set Union (DSU) / Union-Find veri yapısı"""
    
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n
    
    def find(self, x):
        """Kök düğümü bul (path compression ile)"""
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        """İki kümeyi birleştir (union by rank)"""
        px, py = self.find(x), self.find(y)
        if px == py:
            return False  # Zaten aynı kümedeler
        
        # Rank'e göre birleştir
        if self.rank[px] < self.rank[py]:
            px, py = py, px
        self.parent[py] = px
        if self.rank[px] == self.rank[py]:
            self.rank[px] += 1
        return True


def kruskal_mst(n, edges):
    """
    Kruskal algoritması ile MST bul
    
    Args:
        n: Düğüm sayısı
        edges: [(weight, u, v), ...] kenar listesi
    
    Returns:
        MST kenarları ve toplam ağırlık
    """
    # Kenarları ağırlığa göre sırala
    edges.sort()
    
    uf = UnionFind(n)
    mst = []
    total_weight = 0
    
    for weight, u, v in edges:
        # Döngü oluşturmuyorsa ekle
        if uf.union(u, v):
            mst.append((u, v, weight))
            total_weight += weight
            print(f"  ✅ Kenar ({u}-{v}, ağırlık={weight}) eklendi")
            
            # N-1 kenar bulunca dur
            if len(mst) == n - 1:
                break
        else:
            print(f"  ❌ Kenar ({u}-{v}) döngü oluşturur, atlandı")
    
    return mst, total_weight


# Örnek: Şehirler arası kablo döşeme
print("=== KRUSKAL ALGORİTMASI ===")
print("Şehirler: 0=Ankara, 1=İstanbul, 2=İzmir, 3=Bursa, 4=Antalya\n")

# (ağırlık, kaynak, hedef)
edges = [
    (4, 0, 1),   # Ankara-İstanbul
    (8, 0, 2),   # Ankara-İzmir
    (5, 0, 3),   # Ankara-Bursa
    (10, 0, 4),  # Ankara-Antalya
    (2, 1, 3),   # İstanbul-Bursa
    (6, 2, 3),   # İzmir-Bursa
    (3, 2, 4),   # İzmir-Antalya
    (7, 3, 4),   # Bursa-Antalya
]

print("Kenarlar işleniyor (ağırlığa göre sıralı):\n")
mst, total = kruskal_mst(5, edges)

print(f"\n🌲 MST Kenarları: {mst}")
print(f"📏 Toplam Maliyet: {total} birim")
Çıktı bekleniyor...
Prim Algoritması - Priority Queue ile
import heapq
from collections import defaultdict

def prim_mst(n, edges, start=0):
    """
    Prim algoritması ile MST bul
    
    Dijkstra'ya çok benzer! Fark:
    - Dijkstra: Başlangıçtan toplam mesafe
    - Prim: Sadece o kenara mesafe
    
    Args:
        n: Düğüm sayısı
        edges: [(u, v, weight), ...] kenar listesi
        start: Başlangıç düğümü
    
    Returns:
        MST kenarları ve toplam ağırlık
    """
    # Adjacency list oluştur
    graph = defaultdict(list)
    for u, v, w in edges:
        graph[u].append((v, w))
        graph[v].append((u, w))
    
    visited = set()
    mst = []
    total_weight = 0
    
    # Min heap: (weight, from_node, to_node)
    # Başlangıç düğümü için dummy kenar
    pq = [(0, -1, start)]
    
    while pq and len(visited) < n:
        weight, from_node, to_node = heapq.heappop(pq)
        
        if to_node in visited:
            continue
        
        visited.add(to_node)
        
        if from_node != -1:
            mst.append((from_node, to_node, weight))
            total_weight += weight
            print(f"  ✅ Düğüm {to_node} eklendi (kenar: {from_node}-{to_node}, ağırlık={weight})")
        else:
            print(f"  🚀 Başlangıç düğümü: {to_node}")
        
        # Komşuları heap'e ekle
        for neighbor, edge_weight in graph[to_node]:
            if neighbor not in visited:
                heapq.heappush(pq, (edge_weight, to_node, neighbor))
    
    return mst, total_weight


# Aynı örnek
print("=== PRİM ALGORİTMASI ===")
print("Şehirler: 0=Ankara, 1=İstanbul, 2=İzmir, 3=Bursa, 4=Antalya\n")

edges = [
    (0, 1, 4),   # Ankara-İstanbul
    (0, 2, 8),   # Ankara-İzmir
    (0, 3, 5),   # Ankara-Bursa
    (0, 4, 10),  # Ankara-Antalya
    (1, 3, 2),   # İstanbul-Bursa
    (2, 3, 6),   # İzmir-Bursa
    (2, 4, 3),   # İzmir-Antalya
    (3, 4, 7),   # Bursa-Antalya
]

print("MST oluşturuluyor (Ankara'dan başlayarak):\n")
mst, total = prim_mst(5, edges, start=0)

print(f"\n🌲 MST Kenarları: {mst}")
print(f"📏 Toplam Maliyet: {total} birim")
Çıktı bekleniyor...

⚖️ Kruskal vs Prim Karşılaştırması

Kruskal Prim
Yaklaşım Kenar odaklı (global) Düğüm odaklı (local)
Karmaşıklık O(E log E) O(E log V)
Seyrek graf ✅ Daha iyi 🔶 Orta
Yoğun graf 🔶 Orta ✅ Daha iyi
Veri yapısı Union-Find Priority Queue

🛤️ Özel Yol Türleri: Euler ve Hamilton

🔵 Euler Yolu/Devresi

Her kenardan tam bir kez geçen yol/devre

  • Euler Yolu: Her kenardan 1 kez geç, farklı noktada bitebilir
  • Euler Devresi: Her kenardan 1 kez geç, başlangıca dön

📚 Tarihçe: Königsberg'in 7 Köprüsü (1736)

🔴 Hamilton Yolu/Devresi

Her düğümden tam bir kez geçen yol/devre

  • Hamilton Yolu: Her düğümü 1 kez ziyaret et
  • Hamilton Devresi: Her düğümü 1 kez ziyaret et, başlangıca dön

⚠️ NP-Complete problem!

📋 Euler Yolu/Devresi Var mı? - Hızlı Kontrol

Koşul Euler Yolu Euler Devresi
Graf bağlı mı? ✅ Evet ✅ Evet
Tek dereceli düğüm sayısı 0 veya 2 0 (tüm düğümler çift dereceli)

🗑️ Çöp Toplama

Euler yolu: Her sokaktan bir kez geç (çöp kamyonu rotası)

📮 Posta Dağıtımı

Euler yolu: Tüm caddelere uğra, minimum tekrar

🧬 DNA Sequencing

Euler yolu: k-mer parçalarını birleştirme

🎯 Gezgin Satıcı

Hamilton devresi: Tüm şehirleri en kısa yoldan ziyaret et

Euler Yolu/Devresi Kontrolü ve Bulma
from collections import defaultdict, deque

class EulerGraph:
    """Euler yolu ve devresi algoritmaları"""
    
    def __init__(self, directed=False):
        self.graph = defaultdict(list)
        self.directed = directed
    
    def add_edge(self, u, v):
        self.graph[u].append(v)
        if not self.directed:
            self.graph[v].append(u)
    
    def degree(self, v):
        """Düğümün derecesi (yönsüz graf için)"""
        return len(self.graph[v])
    
    def is_connected(self):
        """Graf bağlı mı? (BFS ile kontrol)"""
        if not self.graph:
            return True
        
        start = next(iter(self.graph))
        visited = set()
        queue = deque([start])
        
        while queue:
            node = queue.popleft()
            if node in visited:
                continue
            visited.add(node)
            for neighbor in self.graph[node]:
                if neighbor not in visited:
                    queue.append(neighbor)
        
        return len(visited) == len(self.graph)
    
    def has_euler_path(self):
        """Euler yolu var mı?"""
        if not self.is_connected():
            return False, "Graf bağlı değil"
        
        odd_degree_count = sum(1 for v in self.graph if self.degree(v) % 2 == 1)
        
        if odd_degree_count == 0:
            return True, "Euler DEVRESİ var (tüm dereceler çift)"
        elif odd_degree_count == 2:
            return True, "Euler YOLU var (2 tek dereceli düğüm)"
        else:
            return False, f"Euler yolu yok ({odd_degree_count} tek dereceli düğüm)"
    
    def find_euler_path(self):
        """
        Hierholzer algoritması ile Euler yolu bul
        """
        has_path, msg = self.has_euler_path()
        if not has_path:
            return None, msg
        
        # Çalışma kopyası
        temp_graph = defaultdict(list)
        for v in self.graph:
            temp_graph[v] = self.graph[v].copy()
        
        # Başlangıç: tek dereceli varsa oradan, yoksa herhangi birinden
        start = None
        for v in temp_graph:
            if len(temp_graph[v]) % 2 == 1:
                start = v
                break
        if start is None:
            start = next(iter(temp_graph))
        
        stack = [start]
        path = []
        
        while stack:
            v = stack[-1]
            if temp_graph[v]:
                u = temp_graph[v].pop()
                # Yönsüz graf için karşı kenarı da sil
                if not self.directed:
                    temp_graph[u].remove(v)
                stack.append(u)
            else:
                path.append(stack.pop())
        
        return path[::-1], msg


# Örnek: Königsberg Köprüleri benzeri
print("=== EULER YOLU ANALİZİ ===\n")

# Örnek 1: Euler devresi olan graf
g1 = EulerGraph()
edges1 = [(0, 1), (1, 2), (2, 3), (3, 0), (0, 2)]
for u, v in edges1:
    g1.add_edge(u, v)

print("Graf 1 (kare + çapraz):")
print("Kenarlar:", edges1)
has_path, msg = g1.has_euler_path()
print(f"Sonuç: {msg}")
if has_path:
    path, _ = g1.find_euler_path()
    print(f"Euler yolu: {' → '.join(map(str, path))}")

print("\n" + "="*40 + "\n")

# Örnek 2: Euler yolu olan graf (devre değil)
g2 = EulerGraph()
edges2 = [(0, 1), (1, 2), (2, 0), (2, 3)]
for u, v in edges2:
    g2.add_edge(u, v)

print("Graf 2 (üçgen + kuyruk):")
print("Kenarlar:", edges2)
has_path, msg = g2.has_euler_path()
print(f"Sonuç: {msg}")
if has_path:
    path, _ = g2.find_euler_path()
    print(f"Euler yolu: {' → '.join(map(str, path))}")
Çıktı bekleniyor...
Hamilton Yolu - Backtracking ile
def find_hamiltonian_path(graph, n):
    """
    Hamilton yolu bul - Backtracking
    
    ⚠️ Karmaşıklık: O(n!) - NP-Complete problem!
    Küçük graflar için uygundur.
    """
    
    def backtrack(path, visited):
        # Tüm düğümler ziyaret edildi mi?
        if len(path) == n:
            return path.copy()
        
        current = path[-1]
        
        for neighbor in graph[current]:
            if neighbor not in visited:
                visited.add(neighbor)
                path.append(neighbor)
                
                result = backtrack(path, visited)
                if result:
                    return result
                
                # Backtrack
                path.pop()
                visited.remove(neighbor)
        
        return None
    
    # Her düğümden başlamayı dene
    for start in range(n):
        path = [start]
        visited = {start}
        result = backtrack(path, visited)
        if result:
            return result
    
    return None


def find_hamiltonian_cycle(graph, n):
    """Hamilton devresi bul (başlangıca dönmeli)"""
    
    def backtrack(path, visited):
        if len(path) == n:
            # Son düğümden başlangıca kenar var mı?
            if path[0] in graph[path[-1]]:
                return path + [path[0]]
            return None
        
        current = path[-1]
        
        for neighbor in graph[current]:
            if neighbor not in visited:
                visited.add(neighbor)
                path.append(neighbor)
                
                result = backtrack(path, visited)
                if result:
                    return result
                
                path.pop()
                visited.remove(neighbor)
        
        return None
    
    path = [0]
    visited = {0}
    return backtrack(path, visited)


# Test
print("=== HAMİLTON YOLU ANALİZİ ===\n")

# Graf: 5 düğümlü pentagon
n = 5
graph = {
    0: [1, 4],
    1: [0, 2],
    2: [1, 3],
    3: [2, 4],
    4: [3, 0]
}

print("Graf: Pentagon (5 düğüm)")
print("Kenarlar: 0-1, 1-2, 2-3, 3-4, 4-0\n")

path = find_hamiltonian_path(graph, n)
if path:
    print(f"✅ Hamilton Yolu: {' → '.join(map(str, path))}")
else:
    print("❌ Hamilton yolu bulunamadı")

cycle = find_hamiltonian_cycle(graph, n)
if cycle:
    print(f"✅ Hamilton Devresi: {' → '.join(map(str, cycle))}")
else:
    print("❌ Hamilton devresi bulunamadı")

print("\n" + "="*40 + "\n")

# Daha karmaşık graf
n2 = 4
graph2 = {
    0: [1, 2],
    1: [0, 2, 3],
    2: [0, 1, 3],
    3: [1, 2]
}

print("Graf 2: Tam dörtgen (K4)")
path2 = find_hamiltonian_path(graph2, n2)
cycle2 = find_hamiltonian_cycle(graph2, n2)
print(f"Hamilton Yolu: {' → '.join(map(str, path2)) if path2 else 'Yok'}")
print(f"Hamilton Devresi: {' → '.join(map(str, cycle2)) if cycle2 else 'Yok'}")
Çıktı bekleniyor...

🧳 Gezgin Satıcı Problemi (TSP)

📚 TSP Nedir?

Bir satıcı, tüm şehirleri tam olarak bir kez ziyaret edip başlangıç noktasına dönmek istiyor. En kısa toplam mesafeyi bulmak istiyoruz.

  • Bu aslında minimum ağırlıklı Hamilton Devresi problemidir
  • NP-Hard problem - optimal çözüm için O(n!) veya O(n² × 2ⁿ)
  • Pratik uygulamalarda yaklaşık (heuristic) algoritmalar kullanılır

📦 Lojistik

Kargo dağıtım rotası optimizasyonu (UPS, FedEx)

🔧 Üretim

CNC makinelerinde delik delme sırası

🧬 Genom

DNA sıralama ve genom assembly

📡 Ağ

Veri paketlerinin optimal yönlendirilmesi

TSP - Brute Force ve Dinamik Programlama
from itertools import permutations
import time

def tsp_brute_force(dist_matrix):
    """
    TSP - Brute Force (Kaba Kuvvet)
    
    Tüm permütasyonları dene: O(n!)
    Sadece küçük n için (n ≤ 10)
    """
    n = len(dist_matrix)
    cities = list(range(1, n))  # 0'dan başla, diğerlerini permüte et
    
    min_cost = float('inf')
    best_path = None
    
    for perm in permutations(cities):
        path = [0] + list(perm) + [0]
        cost = sum(dist_matrix[path[i]][path[i+1]] for i in range(n))
        
        if cost < min_cost:
            min_cost = cost
            best_path = path
    
    return best_path, min_cost


def tsp_dp(dist_matrix):
    """
    TSP - Dinamik Programlama (Held-Karp)
    
    Karmaşıklık: O(n² × 2ⁿ)
    Brute force'dan çok daha hızlı ama hala exponential
    """
    n = len(dist_matrix)
    
    # dp[mask][i] = mask kümesindeki şehirleri ziyaret edip i'de biten min maliyet
    # mask: hangi şehirlerin ziyaret edildiğini gösteren bitmask
    INF = float('inf')
    dp = [[INF] * n for _ in range(1 << n)]
    parent = [[-1] * n for _ in range(1 << n)]
    
    # Başlangıç: 0'dan başla
    dp[1][0] = 0
    
    for mask in range(1 << n):
        for last in range(n):
            if dp[mask][last] == INF:
                continue
            if not (mask & (1 << last)):
                continue
            
            for next_city in range(n):
                if mask & (1 << next_city):
                    continue  # Zaten ziyaret edilmiş
                
                new_mask = mask | (1 << next_city)
                new_cost = dp[mask][last] + dist_matrix[last][next_city]
                
                if new_cost < dp[new_mask][next_city]:
                    dp[new_mask][next_city] = new_cost
                    parent[new_mask][next_city] = last
    
    # Tüm şehirler ziyaret edildi, 0'a dön
    full_mask = (1 << n) - 1
    min_cost = INF
    last_city = -1
    
    for i in range(1, n):
        cost = dp[full_mask][i] + dist_matrix[i][0]
        if cost < min_cost:
            min_cost = cost
            last_city = i
    
    # Yolu reconstruct et
    path = [0]
    mask = full_mask
    current = last_city
    
    while current != 0:
        path.append(current)
        prev = parent[mask][current]
        mask ^= (1 << current)
        current = prev
    
    path.append(0)
    path.reverse()
    
    return path, min_cost


# Örnek: 5 şehir
print("=== GEZGİN SATICI PROBLEMİ ===\n")

# Mesafe matrisi (şehirler arası mesafeler)
dist = [
    [0, 10, 15, 20, 25],
    [10, 0, 35, 25, 30],
    [15, 35, 0, 30, 20],
    [20, 25, 30, 0, 15],
    [25, 30, 20, 15, 0]
]

city_names = ["Ankara", "İstanbul", "İzmir", "Bursa", "Antalya"]

print("Şehirler:", city_names)
print("\nMesafe Matrisi:")
print("      ", "  ".join(f"{c[:3]:>5}" for c in city_names))
for i, row in enumerate(dist):
    print(f"{city_names[i][:3]:>5}:", " ".join(f"{d:>5}" for d in row))

print("\n--- Brute Force Çözüm ---")
start = time.time()
path_bf, cost_bf = tsp_brute_force(dist)
time_bf = time.time() - start
print(f"En iyi rota: {' → '.join(city_names[i] for i in path_bf)}")
print(f"Toplam mesafe: {cost_bf}")
print(f"Süre: {time_bf*1000:.2f} ms")

print("\n--- Dinamik Programlama (Held-Karp) ---")
start = time.time()
path_dp, cost_dp = tsp_dp(dist)
time_dp = time.time() - start
print(f"En iyi rota: {' → '.join(city_names[i] for i in path_dp)}")
print(f"Toplam mesafe: {cost_dp}")
print(f"Süre: {time_dp*1000:.2f} ms")
Çıktı bekleniyor...
TSP - Greedy ve 2-Opt Yaklaşık Çözümler
def tsp_greedy(dist_matrix):
    """
    TSP - Greedy (Açgözlü) Yaklaşım
    
    Her adımda en yakın ziyaret edilmemiş şehre git
    Karmaşıklık: O(n²)
    Optimal değil ama hızlı!
    """
    n = len(dist_matrix)
    visited = [False] * n
    path = [0]
    visited[0] = True
    total_cost = 0
    
    for _ in range(n - 1):
        current = path[-1]
        nearest = -1
        min_dist = float('inf')
        
        for next_city in range(n):
            if not visited[next_city] and dist_matrix[current][next_city] < min_dist:
                min_dist = dist_matrix[current][next_city]
                nearest = next_city
        
        path.append(nearest)
        visited[nearest] = True
        total_cost += min_dist
    
    # Başlangıca dön
    total_cost += dist_matrix[path[-1]][0]
    path.append(0)
    
    return path, total_cost


def tsp_2opt(dist_matrix, initial_path=None):
    """
    TSP - 2-Opt İyileştirme
    
    Mevcut bir rotayı 2 kenarı değiştirerek iyileştir
    Local optimum'a ulaşana kadar tekrarla
    """
    n = len(dist_matrix)
    
    if initial_path is None:
        path, _ = tsp_greedy(dist_matrix)
    else:
        path = initial_path.copy()
    
    def calculate_cost(p):
        return sum(dist_matrix[p[i]][p[i+1]] for i in range(len(p)-1))
    
    improved = True
    iterations = 0
    
    while improved:
        improved = False
        iterations += 1
        
        for i in range(1, n - 1):
            for j in range(i + 1, n):
                # 2-opt swap: i ile j arasını ters çevir
                new_path = path[:i] + path[i:j+1][::-1] + path[j+1:]
                
                new_cost = calculate_cost(new_path)
                old_cost = calculate_cost(path)
                
                if new_cost < old_cost:
                    path = new_path
                    improved = True
    
    return path, calculate_cost(path), iterations


# Daha büyük örnek: 8 şehir
print("=== TSP YAKLAŞIK ÇÖZÜMLER ===\n")

import random
random.seed(42)

n = 8
# Rastgele mesafe matrisi (simetrik)
dist = [[0] * n for _ in range(n)]
for i in range(n):
    for j in range(i+1, n):
        d = random.randint(10, 100)
        dist[i][j] = d
        dist[j][i] = d

print(f"Şehir sayısı: {n}")
print(f"Brute force permütasyon sayısı: {n}! = {__import__('math').factorial(n):,}")

print("\n--- Greedy Çözüm ---")
path_g, cost_g = tsp_greedy(dist)
print(f"Rota: {' → '.join(map(str, path_g))}")
print(f"Maliyet: {cost_g}")

print("\n--- 2-Opt İyileştirme ---")
path_2opt, cost_2opt, iters = tsp_2opt(dist)
print(f"Rota: {' → '.join(map(str, path_2opt))}")
print(f"Maliyet: {cost_2opt}")
print(f"İterasyon: {iters}")

improvement = (cost_g - cost_2opt) / cost_g * 100
print(f"\n📈 2-Opt iyileştirmesi: %{improvement:.1f} daha iyi")
Çıktı bekleniyor...

💼 Graf Mülakat Soruları

Yazılım mülakatlarda sıkça karşılaşılan graf problemleri. Önce kendiniz çözmeyi deneyin!

1. Adaları Say (Number of Islands) Orta

2D bir grid verildiğinde, "1" kara ve "0" su temsil eder. Birbirine bağlı (4 yönde) kara parçalarından oluşan ada sayısını bulun. (LeetCode #200)

Örnek:
grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
Output: 3
💡 İpucu: Her "1" hücresinden DFS/BFS başlat ve bağlı tüm karaları ziyaret et.
2. Ders Sıralaması (Course Schedule) Orta

numCourses ders ve prerequisites ön koşul listesi verildiğinde, tüm dersleri bitirebilir misiniz? (LeetCode #207)

Örnek:
numCourses = 4
prerequisites = [[1,0], [2,1], [3,2]]
Output: True (0→1→2→3 sırasıyla alınabilir)
💡 İpucu: Döngü var mı? Topological sort yapılabilir mi?
3. Kelime Merdiveni (Word Ladder) Zor

beginWord'den endWord'e dönüşmek için gereken minimum adım sayısını bulun. Her adımda sadece 1 harf değiştirebilirsiniz ve ara kelimeler wordList'te olmalı. (LeetCode #127)

Örnek:
beginWord = "hit", endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
Output: 5 (hit → hot → dot → dog → cog)
4. Çürüyen Portakallar (Rotting Oranges) Orta

Bir grid'de 0=boş, 1=taze portakal, 2=çürük portakal. Her dakika çürük portakallar komşu taze portakalları çürütür. Tüm portakalların çürümesi için minimum dakika bulun. (LeetCode #994)

💡 İpucu: Multi-source BFS - tüm çürük portakallardan aynı anda başla!
5. Graf Klonlama (Clone Graph) Orta

Verilen bir grafın derin kopyasını (deep clone) oluşturun. (LeetCode #133)

📊 Özet: Hangi Problem için Hangi Algoritma?

Problem Algoritma Neden?
En kısa yol (ağırlıksız) BFS Seviye sırasında arar, O(V+E)
En kısa yol (ağırlıklı) Dijkstra Pozitif ağırlıklar, O((V+E)logV)
Bağımlılık sıralaması Topological Sort DAG'larda görev sırası, O(V+E)
Döngü tespiti DFS Back edge kontrolü, O(V+E)
Bağlantılı bileşenler BFS/DFS Her ikisi de çalışır, O(V+E)
Tüm çiftler en kısa yol Floyd-Warshall Dinamik programlama, O(V³)
Minimum yayılan ağaç Kruskal / Prim Greedy yaklaşım, O(E log E)
Euler yolu/devresi Hierholzer Derece kontrolü + DFS, O(E)
Hamilton yolu/devresi Backtracking NP-Complete, O(n!)
Gezgin satıcı (TSP) DP / Greedy+2-Opt Optimal O(n²2ⁿ), yaklaşık O(n²)