🔴 Сложный ⏱️ 25 минут

Топологическая сортировка: как построить правильную очередь

Топологическая сортировка: как построить правильную очередь

🎯 Зачем это нужно?

Представь, что ты собираешь компьютер 🖥️. Сначала нужно установить материнскую плату, потом процессор, затем оперативную память, и только после этого видеокарту. Попробуй поставить видеокарту до материнской платы - ничего не получится!

Реальные применения:

  • 🏗️ Планирование проектов: какие задачи делать в каком порядке
  • 💻 Компиляция кода: в каком порядке компилировать файлы с зависимостями
  • 📚 Учебный план: какие предметы изучать до других (алгебру перед матанализом)
  • 🧬 Биоинформатика: порядок активации генов в клетке
  • 🎮 Игровые движки: порядок рендеринга объектов для правильного отображения

📚 История вопроса

Топологическая сортировка появилась в 1960-х для решения проблемы планирования проектов. Артур Кан в 1962 году предложил алгоритм для метода критического пути (CPM) в управлении проектами.

Забавный факт: каждый раз, когда npm устанавливает пакеты в правильном порядке зависимостей, он использует топологическую сортировку! 📦

💡 Интуиция

Топологическая сортировка - это способ упорядочить элементы так, чтобы для каждой стрелки A → B элемент A шёл раньше B в итоговой последовательности.

Аналогия с одеванием утром:

  • Носки → Ботинки ✅
  • Ботинки → Носки ❌ (так не получится!)

Математически: если есть ребро u → v, то u должно идти перед v в топологически отсортированном порядке.

[МЕДИА: image_01] Описание: Граф зависимостей для сборки компьютера с узлами “материнская плата”, “процессор”, “RAM”, “видеокарта” и стрелками показывающими порядок установки Промпт: “directed acyclic graph showing computer assembly dependencies, nodes labeled with computer parts (motherboard, CPU, RAM, GPU), arrows showing installation order, clean technical illustration style, blue and orange color scheme”

📐 Формальное определение

Определение: Топологическая сортировка направленного ациклического графа (DAG) - это линейное упорядочивание всех вершин такое, что если существует ребро (u,v), то u появляется раньше v в упорядочивании.

Важно: Топологическая сортировка возможна только для DAG (Directed Acyclic Graph) - графов без циклов!

Свойства:

  • Граф может иметь несколько различных топологических сортировок
  • Если граф содержит цикл, топологической сортировки не существует
  • Алгоритм имеет сложность O(V + E)

🔍 Примеры с разбором

Пример 1: Алгоритм Кана (BFS-подход)

Пусть у нас есть граф курсов университета:

Алгебра → Матанализ → Диффуры
    ↓         ↓
Геометрия → Топология

Шаг 1: Считаем входящие степени

  • Алгебра: 0 (никто не указывает на неё)
  • Геометрия: 1 (Алгебра → Геометрия)
  • Матанализ: 1 (Алгебра → Матанализ)
  • Топология: 2 (Геометрия → Топология, Матанализ → Топология)
  • Диффуры: 1 (Матанализ → Диффуры)

Шаг 2: В очередь добавляем вершины с нулевой степенью Очередь: [Алгебра]

Шаг 3: Обрабатываем Алгебру

  • Результат: [Алгебра]
  • Уменьшаем степени соседей: Геометрия(0), Матанализ(0)
  • Очередь: [Геометрия, Матанализ]

Шаг 4: Обрабатываем Геометрию

  • Результат: [Алгебра, Геометрия]
  • Уменьшаем степень Топологии: Топология(1)
  • Очередь: [Матанализ]

Шаг 5: Обрабатываем Матанализ

  • Результат: [Алгебра, Геометрия, Матанализ]
  • Уменьшаем степени: Топология(0), Диффуры(0)
  • Очередь: [Топология, Диффуры]

Итоговый порядок: Алгебра → Геометрия → Матанализ → Топология → Диффуры

[МЕДИА: image_02] Описание: Пошаговая визуализация алгоритма Кана с очередью и изменяющимися степенями вершин Промпт: “step-by-step visualization of Kahns algorithm, graph with in-degrees labeled, queue showing current state, nodes being processed highlighted, educational algorithm animation style”

Пример 2: DFS-подход

Тот же граф, но используем обход в глубину:

def topological_sort_dfs(graph):
    visited = set()
    stack = []
    
    def dfs(node):
        if node in visited:
            return
        visited.add(node)
        
        for neighbor in graph[node]:
            dfs(neighbor)
        
        stack.append(node)  # Добавляем ПОСЛЕ обработки детей
    
    for node in graph:
        if node not in visited:
            dfs(node)
    
    return stack[::-1]  # Разворачиваем стек

Ключевая идея: добавляем вершину в результат только после того, как обработали всех её “потомков”.

🎮 Практика

Базовый уровень 🟢

Задание 1: У тебя есть задачи: A→B, B→C, A→C. Найди топологический порядок.

💡 Подсказка Начни с вершины без входящих рёбер
✅ Ответ A → B → C (A имеет входящую степень 0)

Задание 2: Можно ли топологически отсортировать граф A→B→C→A?

💡 Подсказка Есть ли в графе циклы?
✅ Ответ Нет, граф содержит цикл A→B→C→A

Задание 3: Реализуй алгоритм Кана для графа: {A: [B,C], B: [D], C: [D], D: []}

✅ Ответ Входящие степени: A(0), B(1), C(1), D(2). Результат: A → B → C → D (или A → C → B → D)

Продвинутый уровень 🟡

Задание 4: В проекте есть задачи со временем выполнения. Как найти критический путь?

💡 Подсказка Топологическая сортировка + динамическое программирование

Задание 5: Как обнаружить цикл в процессе топологической сортировки?

✅ Ответ В алгоритме Кана: если обработали не все вершины, есть цикл. В DFS: если встретили серую вершину.

Задание 6: Найди все возможные топологические сортировки графа A→C, B→C

✅ Ответ A→B→C, B→A→C (C всегда последний)

Челлендж 🔴

Задание 7: Реализуй топологическую сортировку с лексикографическим порядком

💡 Подсказка Используй приоритетную очередь вместо обычной в алгоритме Кана

Задание 8: Как найти минимальное количество семестров для изучения всех курсов?

✅ Ответ Длина самого длинного пути в DAG (критический путь)

⚠️ Частые ошибки

Ошибка: “Топологическая сортировка всегда единственна” ✅ Правильно: Может быть несколько различных правильных порядков 💡 Почему: Если нет прямой зависимости между элементами, их можно менять местами

Ошибка: “Можно топологически отсортировать любой граф”
Правильно: Только направленные ациклические графы (DAG) 💡 Почему: Циклы создают противоречия в порядке

Ошибка: В DFS добавлять вершину в результат при первом посещении ✅ Правильно: Добавлять после обработки всех потомков 💡 Почему: Иначе нарушится правильный порядок зависимостей

🎓 Главное запомнить

✅ Топологическая сортировка упорядочивает элементы с учётом зависимостей ✅ Работает только для DAG (графов без циклов)
✅ Алгоритм Кана: BFS с подсчётом входящих степеней ✅ DFS-подход: добавляем в результат после обработки потомков ✅ Применяется везде: от компиляторов до планирования проектов

🔗 Связь с другими темами

Назад: Обход графов (урок 261) дал нам основы DFS и BFS Вперёд: Поиск сильно связных компонент, алгоритмы на DAG, критический путь в проектах Практика: Системы сборки (Make, CMake), пакетные менеджеры, планировщики задач

Понял тему? Закрепи в боте! 🚀

Попрактикуйся на задачах и получи персональные рекомендации от AI

💪 Начать тренировку
💬 Есть вопрос? Спроси бота!