Топологическая сортировка (Topological sort) — один из основных алгоритмов на графах, который применяется для решения множества более сложных задач.
Задача топологической сортировки графа состоит в следующем: указать такой линейный порядок на его вершинах, чтобы любое ребро вело от вершины с меньшим номером к вершине с большим номером. Очевидно, что если в графе есть циклы, то такого порядка не существует.
Ориентированной сетью (или просто сетью) называют бесконтурный ориентированный граф. В задачах подобного плана рассматриваются только конечные сети.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/35e/35d/4c8/35e35d4c8a6cae349621fd71ae20046d.png)
Из рисунка видно, что граф не отсортирован, так как ребро из вершины с номером 4 ведет в вершину с меньшим номером (2).
Существует несколько способов топологической сортировки — из наиболее известных:
Поиск в глубину или обход в глубину (англ. Depth-first search, сокращенно DFS) — один из методов обхода графа. Алгоритм поиска описывается следующим образом: для каждой не пройденной вершины необходимо найти все не пройденные смежные вершины и повторить поиск для них.
Подробнее о поиске в глубину можно почитать в статье на Хабре.
Запускаем обход в глубину, и когда вершина обработана, заносим ее в стек. По окончании обхода в глубину вершины достаются из стека. Новые номера присваиваются в порядке вытаскивания из стека.
Цвет: во время обхода в глубину используется 3 цвета. Изначально все вершины белые. Когда вершина обнаружена, красим ее в серый цвет. Когда просмотрен список всех смежных с ней вершин, красим ее в черный цвет.
Думаю будет проще рассмотреть данный алгоритм на примере:
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/35e/35d/4c8/35e35d4c8a6cae349621fd71ae20046d.png)
↑ Имеем бесконтурный ориентированный граф. Изначально все вершины белые, а стек пуст. Начнем обход в глубину с вершины номер 1.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/ba9/255/233/ba9255233c1ee35faf1c734220d2ab1c.png)
↑ Переходим к вершине номер 1. Красим ее в серый цвет.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/d0a/161/4dc/d0a1614dc442075029b7fa9101c80728.png)
↑ Существует ребро из вершины номер 1 в вершину номер 4. Переходим к вершине номер 4 и красим ее в серый цвет.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/7a4/ff0/6ba/7a4ff06ba07b53314e58ef4d70b09771.png)
↑ Существует ребро из вершины номер 4 в вершину номер 2. Переходим к вершине номер 2 и красим ее в серый цвет.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/343/f1f/b03/343f1fb03ae250a44110b70fd57d0ef1.png)
↑ Из вершины номер 2 нет рёбер, идущих не в черные вершины. Возвращаемся к вершине номер 4. Красим вершину номер 2 в черный цвет и кладем ее в стек.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/570/472/867/57047286796cbc05c18d20af5cc1b930.png)
↑ Существует ребро из вершины номер 4 в вершину номер 3. Переходим к вершине номер 3 и красим ее в серый цвет.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/676/b74/468/676b74468e19c8303402b6aa1b65ac83.png)
↑ Из вершины номер 3 нет рёбер, идущих не в черные вершины. Возвращаемся к вершине номер 4. Красим вершину номер 3 в черный цвет и кладем ее в стек.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/cfd/f09/806/cfdf09806e17b453a61052dc4c371501.png)
↑ Из вершины номер 4 нет рёбер, идущих не в черные вершины. Возвращаемся к вершине номер 1. Красим вершину номер 4 в черный цвет и кладем ее в стек.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/f60/b0d/79a/f60b0d79acc12c57d85bdb6ef4a07c44.png)
↑ Из вершины номер 1 нет рёбер, идущих не в черные вершины. Красим её в черный цвет и кладем в стек. Обход точек закончен.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/02e/6c8/693/02e6c869388a84317214d1659b40b44c.png)
↑ По очереди достаем все вершины из стека и присваиваем им номера 1, 2, 3, 4 соответсвенно. Алгоритм топологической сортировки завершен. Граф отсортирован.
Топологическая сортировка применяется в самых разных ситуациях, например при распараллеливании алгоритмов, когда по некоторому описанию алгоритма нужно составить граф зависимостей его операций и, отсортировав его топологически, определить, какие из операций являются независимыми и могут выполняться параллельно (одновременно). Примером использования топологической сортировки может служить создание карты сайта, где имеет место древовидная система разделов. (если интересно — to google)
Что касается реализации — здесь Вы можете найти 22 строчки кода, реализующих данный алгоритм (все тщательно закомментировано)
Задача топологической сортировки графа состоит в следующем: указать такой линейный порядок на его вершинах, чтобы любое ребро вело от вершины с меньшим номером к вершине с большим номером. Очевидно, что если в графе есть циклы, то такого порядка не существует.
Ориентированной сетью (или просто сетью) называют бесконтурный ориентированный граф. В задачах подобного плана рассматриваются только конечные сети.
![image](https://habrastorage.org/getpro/habr/post_images/35e/35d/4c8/35e35d4c8a6cae349621fd71ae20046d.png)
↑ Пример ориентированного неотсортированного графа, к которому применима топологическая сортировка
Из рисунка видно, что граф не отсортирован, так как ребро из вершины с номером 4 ведет в вершину с меньшим номером (2).
Существует несколько способов топологической сортировки — из наиболее известных:
- Алгоритм Демукрона
- Метод сортировки для представления графа в виде нескольких уровней
- Метод топологической сортировки с помощью обхода в глубину
Суть алгоритма
Поиск в глубину или обход в глубину (англ. Depth-first search, сокращенно DFS) — один из методов обхода графа. Алгоритм поиска описывается следующим образом: для каждой не пройденной вершины необходимо найти все не пройденные смежные вершины и повторить поиск для них.
Подробнее о поиске в глубину можно почитать в статье на Хабре.
Запускаем обход в глубину, и когда вершина обработана, заносим ее в стек. По окончании обхода в глубину вершины достаются из стека. Новые номера присваиваются в порядке вытаскивания из стека.
Цвет: во время обхода в глубину используется 3 цвета. Изначально все вершины белые. Когда вершина обнаружена, красим ее в серый цвет. Когда просмотрен список всех смежных с ней вершин, красим ее в черный цвет.
Думаю будет проще рассмотреть данный алгоритм на примере:
![image](https://habrastorage.org/getpro/habr/post_images/35e/35d/4c8/35e35d4c8a6cae349621fd71ae20046d.png)
↑ Имеем бесконтурный ориентированный граф. Изначально все вершины белые, а стек пуст. Начнем обход в глубину с вершины номер 1.
![image](https://habrastorage.org/getpro/habr/post_images/ba9/255/233/ba9255233c1ee35faf1c734220d2ab1c.png)
↑ Переходим к вершине номер 1. Красим ее в серый цвет.
![image](https://habrastorage.org/getpro/habr/post_images/d0a/161/4dc/d0a1614dc442075029b7fa9101c80728.png)
↑ Существует ребро из вершины номер 1 в вершину номер 4. Переходим к вершине номер 4 и красим ее в серый цвет.
![image](https://habrastorage.org/getpro/habr/post_images/7a4/ff0/6ba/7a4ff06ba07b53314e58ef4d70b09771.png)
↑ Существует ребро из вершины номер 4 в вершину номер 2. Переходим к вершине номер 2 и красим ее в серый цвет.
![image](https://habrastorage.org/getpro/habr/post_images/343/f1f/b03/343f1fb03ae250a44110b70fd57d0ef1.png)
↑ Из вершины номер 2 нет рёбер, идущих не в черные вершины. Возвращаемся к вершине номер 4. Красим вершину номер 2 в черный цвет и кладем ее в стек.
![image](https://habrastorage.org/getpro/habr/post_images/570/472/867/57047286796cbc05c18d20af5cc1b930.png)
↑ Существует ребро из вершины номер 4 в вершину номер 3. Переходим к вершине номер 3 и красим ее в серый цвет.
![image](https://habrastorage.org/getpro/habr/post_images/676/b74/468/676b74468e19c8303402b6aa1b65ac83.png)
↑ Из вершины номер 3 нет рёбер, идущих не в черные вершины. Возвращаемся к вершине номер 4. Красим вершину номер 3 в черный цвет и кладем ее в стек.
![image](https://habrastorage.org/getpro/habr/post_images/cfd/f09/806/cfdf09806e17b453a61052dc4c371501.png)
↑ Из вершины номер 4 нет рёбер, идущих не в черные вершины. Возвращаемся к вершине номер 1. Красим вершину номер 4 в черный цвет и кладем ее в стек.
![image](https://habrastorage.org/getpro/habr/post_images/f60/b0d/79a/f60b0d79acc12c57d85bdb6ef4a07c44.png)
↑ Из вершины номер 1 нет рёбер, идущих не в черные вершины. Красим её в черный цвет и кладем в стек. Обход точек закончен.
![image](https://habrastorage.org/getpro/habr/post_images/02e/6c8/693/02e6c869388a84317214d1659b40b44c.png)
↑ По очереди достаем все вершины из стека и присваиваем им номера 1, 2, 3, 4 соответсвенно. Алгоритм топологической сортировки завершен. Граф отсортирован.
Применение
Топологическая сортировка применяется в самых разных ситуациях, например при распараллеливании алгоритмов, когда по некоторому описанию алгоритма нужно составить граф зависимостей его операций и, отсортировав его топологически, определить, какие из операций являются независимыми и могут выполняться параллельно (одновременно). Примером использования топологической сортировки может служить создание карты сайта, где имеет место древовидная система разделов. (если интересно — to google)
Что касается реализации — здесь Вы можете найти 22 строчки кода, реализующих данный алгоритм (все тщательно закомментировано)