Бесплатная бета: 60 дней полного доступа, без карты.мест осталось: 84Зарегистрироваться бесплатно

Мы используем необходимые куки для работы сайта (вход и язык). Если ты согласишься, мы также загрузим Google Analytics, чтобы видеть, какие страницы читают, и Google reCAPTCHA для защиты форм обратной связи и сообщений об ошибке от спама. Политика конфиденциальности

← Блог
Как готовиться

Алгоритм Кана: топологическая сортировка простыми словами

· 2026-09-26

Короткий ответ. Алгоритм Кана это топологическая сортировка через подсчёт входящих рёбер. Берём вершины, в которые ничего не ведёт, снимаем их, уменьшаем счётчики соседей. Повторяем, пока есть что снимать. Если сняли не все вершины, в графе цикл. Ниже код на Python, где он нужен и на чём он ломается.

Что делает топологическая сортировка?

Она выстраивает вершины ориентированного графа в ряд. Каждое ребро в нём идёт слева направо.

Пример из жизни. Курсы в университете и их зависимости. Топологический порядок это порядок, в котором их можно пройти.

Работает только на графе без циклов. Если A требует B, а B требует A, порядка нет.

Порядок задач по алгоритму Кана
topoSort(6, [[1, 2], [3], [3, 5], [4, 5], [], []])
число над задачей = сколько задач она ещё ждёт
queue (готовы к запуску)
пусто
order
пусто

Стрелка u → v значит, что u должна выполниться раньше v. Считаем входящие стрелки у каждой задачи.

Страница паттерна: когда его применять и шаблон на шести языках

Как работает алгоритм Кана?

Четыре шага, и все они простые.

  • Для каждой вершины считаем, сколько рёбер в неё входит. Это in-degree.
  • Все вершины с in-degree 0 кладём в очередь.
  • Снимаем вершину из очереди, добавляем в ответ. У всех её соседей уменьшаем in-degree на 1.
  • Сосед дошёл до нуля, кладём его в очередь.

Проследим на графе с рёбрами A→C, B→C, C→D.

ШагОчередьСнимаемОтвет
0A, B
1BAA
2CBA, B
3DCA, B, C
4DA, B, C, D

C попал в очередь только на шаге 2. До этого в него вели два ребра, и оба надо было снять.

Как написать алгоритм Кана на Python?

Граф задан списком рёбер. Вершины пронумерованы от 0 до n-1.

from collections import deque

def kahn(n, edges):
    graph = [[] for _ in range(n)]
    indegree = [0] * n
    for a, b in edges:
        graph[a].append(b)
        indegree[b] += 1

    queue = deque(v for v in range(n) if indegree[v] == 0)
    order = []

    while queue:
        v = queue.popleft()
        order.append(v)
        for w in graph[v]:
            indegree[w] -= 1
            if indegree[w] == 0:
                queue.append(w)

    if len(order) != n:
        return None  # в графе есть цикл
    return order

Проверка на цикл встроена. Вершина из цикла никогда не дойдёт до нуля. В ответ она не попадёт.

Сложность O(V + E). Каждую вершину снимаем один раз, каждое ребро уменьшаем один раз.

Когда алгоритм Кана нужен в задаче?

Слова в условии, по которым его узнают.

  • «Курсы и пререквизиты», «можно ли пройти все курсы».
  • «Порядок сборки», «зависимости пакетов», «порядок задач».
  • «Найди любой порядок, в котором…».
  • «Есть ли цикл в ориентированном графе».
  • «Восстанови алфавит по отсортированным словам».

Общий признак: направленные зависимости. Нужен порядок, или проверка, что он существует.

Сигналы, соседи паттерна и шаблоны на шести языках на странице топологической сортировки.

Чем алгоритм Кана отличается от DFS-варианта?

Топологическую сортировку делают двумя способами. Оба дают верный порядок.

  • Кан идёт от вершин без входящих рёбер. Порядок строится с начала.
  • DFS идёт вглубь и записывает вершину при выходе. Ответ переворачивают.
  • Кан находит цикл по счётчику. DFS находит цикл по серой вершине.
  • Кан удобнее, когда нужен порядок «по слоям». Например, задачи, которые можно делать параллельно.

На собеседовании чаще ждут Кана. Его проще объяснить вслух, а это половина оценки.

Как решить Course Schedule алгоритмом Кана?

Условие. Есть n курсов. Пары вида «сначала b, потом a». Можно ли пройти все?

Читаем как граф. Каждая пара это ребро b→a. Вопрос: есть ли в графе цикл.

Запускаем kahn. Вернул порядок, ответ «да». Вернул None, ответ «нет».

Course Schedule II просит сам порядок. Тот же код, возвращаем список вместо да или нет.

Проговорим маленький случай. n = 3, пары (1, 0) и (2, 1). Входящие: 0, 1, 1. В очереди сначала 0. Сняли 0, освободилась 1. Сняли 1, освободилась 2. Порядок: 0, 1, 2.

Добавим пару (0, 2). У всех вершин по одному входящему ребру. Очередь пуста с самого начала, ответ «нет».

Как объяснить алгоритм Кана на собеседовании?

Три фразы до кода, в таком порядке.

  • «Зависимости это ориентированный граф. Нужен топологический порядок.»
  • «Считаю входящие рёбра и начинаю с вершин без них. Снятая вершина освобождает соседей.»
  • «Каждая вершина и каждое ребро трогаются один раз, O(V + E). Порядок короче n, значит цикл.»

Потом код. Потом трассировка на трёх вершинах. Сложность в конце ещё раз.

На чём ломается алгоритм Кана?

Три ошибки, которые встречаются чаще других.

  • Ребро прочитано в обратную сторону. Порядок выходит зеркальный, тесты красные.
  • Забыта проверка len(order) != n. Граф с циклом даёт неполный ответ без ошибки.
  • Вместо очереди взят список с pop(0). Это O(n) на каждый шаг.

Как закрепить алгоритм Кана?

Напиши kahn по памяти. Потом реши Course Schedule и Course Schedule II. Это одна и та же задача, вторая просит порядок.

Через день напиши снова без подглядывания. Как это работает, объяснено в статье про интервальные повторения.

Вопросы и ответы

Какая сложность у алгоритма Кана?

O(V + E) по времени и O(V + E) по памяти на список смежности.

Что вернёт алгоритм Кана на графе с циклом?

Неполный порядок. Поэтому в конце сравнивают длину ответа с числом вершин.

Порядок единственный?

Нет. Если в очереди две вершины, любую можно взять первой. Оба порядка верные.

Почему очередь, а не стек?

Со стеком алгоритм тоже верен. Очередь даёт порядок по слоям, который чаще просят.