Реализация BFS и DFS

Топологический вид DAG — это частичное линейное упорядочение его узлов, такое что, если этот граф имеет ребро, направленное от u к v, u должны быть расположены в порядке перед v. Частичный порядок очень полезен во многих ситуациях. Планирование проблем, разрешение зависимостей.

Некоторые полезные термины для графиков

  • Inстепень — количество ребер, указывающих на него.
  • Outgrade — количество ребер, выходящих из вершины.
  • Исходная вершина — вершина без ребер, указывающих на нее. У него есть края, которые направлены только наружу.
  • Sink Vertex — вершина без исходящих ребер. У него есть края, которые указывают только на него.

Алгоритм Кана (BFS)

Шаги

  1. Сохраните степени входа всех узлов в графе.
  2. Определите узлы со степенью вхождения 0. Добавьте каждый узел в очередь, которая будет повторяться.
  3. Пока набор, содержащий узлы со степенью вхождения 0, не пуст, удалите узел. Сохраните узел в списке результатов. Для каждого удаленного узла выполните итерацию по его краям, уменьшая степень вхождения каждого целевого узла на краю. Если узел теперь имеет степень вхождения 0, добавьте его в очередь и список на шаге 2.
  4. Наконец, верните список, к которому добавлен каждый узел. Это будет содержать топологический порядок узлов.

Реализация кода

from collections import defaultdict
 
class Graph:
    def __init__(self, vertices):
        self.graph = defaultdict(list)
        self.V = vertices
    def add_edge(self, u, v):
        self.graph[u-1].append(v-1)
    def topological_sort(self):
        in_degree = [0]*(self.V)
        visited = [0]*(self.V)
        for i in self.graph:
            for j in self.graph[i]:
                in_degree[j] += 1
        top_order = []
        queue = []
        from heapq import heappush, heappop
        for i in range(self.V):
            if in_degree[i] == 0:
                heappush(queue, i)
        while queue:
            u = heappop(queue)
            if not visited[u]:
                top_order.append(u+1)
                for i in self.graph[u]:
                    in_degree[i] -= 1
                    if in_degree[i] == 0:
                        heappush(queue, i)
                visited[u] = 1
        
        return top_order
## Driver code  
A = 6
B = [[6, 3], [6, 1], [5, 1], [5, 2], [3, 4], [4, 2]]
graph = Graph(A)
for u, v in B:
    graph.add_edge(u, v)
        
res = graph.topological_sort()
print(res) # [5, 6, 1, 3, 4, 2]

В приведенной выше реализации я использовал heapq, так как хотел, чтобы результат был лексикографически наименьшим, если у нас есть несколько заказов. Кроме того, я использовал (u-1 и v-1), так как я использую индексирование узлов на основе 1.

Модифицированный поиск в глубину

Шаги

  1. Начните с любой вершины и вызовите на ней функцию DFS.
  2. Продолжайте двигаться по этому пути, пока не найдете узел, у которого больше нет исходящих ребер.
  3. Добавляем его в топологический порядок (вставляем в стек по 0-му индексу, иначе получим обратный порядок).
  4. Возврат к предыдущему узлу с дальнейшими непосещенными потомками.
  5. Продолжайте, пока не посетите все узлы.

Реализация кода

from collections import defaultdict
 
class Graph:
    def __init__(self, vertices):
        self.graph = defaultdict(list)
        self.V = vertices
    
    def add_edge(self, u, v):
        self.graph[u-1].append(v-1)
    def helper(self,u,visited, res):
        visited[u] = True
        for i in self.graph[u]:
            if visited[i] == False:
                self.helper(i, visited, res)
        res.insert(0, u+1)
    def topological_sort(self):
        visited = [False]*self.V
        res =[]
        for i in reversed(range(self.V)):
            if visited[i] == False:
                self.helper(i, visited, res)
                
        return res
## Driver code
A = 6
B = [[6, 3], [6, 1], [5, 1], [5, 2], [3, 4], [4, 2]]
graph = Graph(A)
for u, v in B:
    graph.add_edge(u, v)
        
res = graph.topological_sort()
print(res) # [5, 6, 1, 3, 4, 2]

В приведенной выше реализации я использовал reverse(range(self.V)) , так как хотел, чтобы результат был лексикографически наименьшим, если у нас есть несколько заказов.

Удачного кодирования!

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Посетите наш Community Discord и присоединитесь к нашему Коллективу талантов.