Graph Algorithms: Depth-First Search, Bellman-Ford, and Euler
Depth-First Search (DFS)
Code:
def _dfs(G, node, verts):
# Add node to visitedverts.add(node)# For each neighborfor neigh in G[node]:# If neighbor not visitedif neigh not in verts:# Start exploration from neighborverts = _dfs(G, neigh, verts)return verts
Connected Components
Code:
def cnx(G):
components = []visited = set()# For every node (so we guarantee that every node is visited even if not connected)for node in G:if node in visited: continue # If already visited, next# Explore (e.g. with DFS) from the given nodecomp = _dfs(G, node, set())# Update visited from that explorationvisited.update(comp)# If DFS finished, a connected component has already been foundcomponents.append(list(comp))return components
Bellman-Ford Algorithm
Code:
def bellman_ford(G, origin, destination):
distance = dict()parent = dict()# Initialize structuresfor node in G.nodes:distance[node] = float('inf')parent[node] = Nonedistance[origin] = 0# Relax the edges node-1 timesfor _ in range(len(G)-1):for u,v in G.edges:new_dist = G[u][v]['weight']if distance[u] + new_dist < distance[v]:distance[v] = distance[u] + new_distparent[v] = u# If when trying to relax the edges one more time we succeed, there is a negative cyclefor u,v in G.edges:new_dist = G[u][v]['weight']if distance[u] + new_dist < distance[v]:print("Negative cycle detected!")return {'path': [],'distance': float('inf')}# Reconstruct the pathpath = []node = destinationwhile node != None:path.append(node)node = parent[node]if path[0] != destination or path[-1] != origin:print("The destination node is not reachable from the origin")return {'path': [],'distance': float('inf')}return {'path': path[::-1],'distance': distance[destination]}
Euler Algorithm
from random import choice
Code:
def euler(G):
# Check if has euler cyclefor node in G.nodes:if G.degree(node) % 2: return []# Visited EDGESvisited = set()# Random starting nodecycles = []path = [choice(list(G))]while len(visited) is not len(G.edges):node = path[-1]for neigh in G.neighbors(node):edge = tuple(sorted([node, neigh]))# Pick unvisited edgeif edge not in visited:path.append(neigh)visited.add(edge)break# Closed loopif path[0] == path[-1]:cycles.append(path)# Search next node on pathfor node in path:edges = set([tuple(sorted([node, n])) for n in G.neighbors(node)])unvisited = edges - visitedif unvisited:path = [node]break# Reconstruct path from cyclespath = []for c in cycles:if not path: path = c # Firstelse:idx = path.index(c[0])path = path[:idx] + c + path[idx+1:]return path
