Is a problem of finding a path between two nodes, such that the sum of the weights of its constituent edges is minimized.
\[ \begin{aligned} &InitializeSingleSource(G,s)\\ &\qquad for \space each \space vertex \space v \in G.V \\ &\qquad \qquad v.d = \infty \\ &\qquad \qquad v.\pi = NIL \\ &\qquad s.d = 0 \\ \end{aligned} \]
\[ \begin{aligned} &Relax(u,v,w)\\ &\qquad if \space v.d > u.d + w(u,v)\\ &\qquad \qquad v.d = u.d + w(u,v)\\ &\qquad \qquad v.\pi = u \\ \end{aligned} \]
\[ \begin{aligned} &Dijkstra(G,w,s)\\ &\qquad InitializeSingleSource(G,s)\\ &\qquad S = \emptyset\\ &\qquad Q = G.V \\ &\qquad while \space Q \neq \emptyset\\ &\qquad \qquad u = ExtractMin(Q) \\ &\qquad \qquad S = S \cup \{u\} \\ &\qquad \qquad for \space each \space v \in G.Adj[u]\\ &\qquad \qquad \qquad Relax(u,v,w)\\ \end{aligned} \]
Green - current node, Red - unvisited node, Blue - target node. Assign distance to the start node as 0, and INF to all others. Assign the start node as the current node.
Updating the distance to neighbors of the current node.
Updating the distance to neighbors of the current node.
Make the second node as current node. Mark the first node is visited.
Updating the distance to neighbors of the current node.
Updating the distance to neighbors of the current node.
Assign node 7 as the current node.
Updating the distance to neighbors of the current node.
Assign node 3 as the current node.
Updating the distance to neighbors of the current node.
Assign node 5 as the current node.
Updating the distance to neighbors of the current node.
Mark the current node as visited.
The algorithm finished.
See other visualizations here: https://www.cs.usfca.edu/~galles/visualization/Dijkstra.html
def dijkstra(graph, start):
props = {
start:{
"distance": 0,
"parent": None,
"visited": False
}
}
while len(filterListDictionaries(props,"visited", False).keys())>0:
u = closestNotVisitedNode(props)
for v in set(graph[u]) - set(filterListDictionaries(props,"visited", True)):
if v not in props:
props[v] = {
"distance": float("inf"),
"parent": None,
"visited": False
}
props = relax(props,u,v,graph[u][v])
props[u]["visited"] = True
return props
def filterListDictionaries(l, f, value):
return {k: v for k, v in l.iteritems() if v[f] == value}
def closestNotVisitedNode(nodes_prop):
not_visited = filterListDictionaries(nodes_prop,"visited", False)
lam = lambda x: not_visited[x]["distance"]
return min(not_visited, key = lam)
def relax(nodes_prop, u, v, w):
if nodes_prop[v]["distance"] > nodes_prop[u]["distance"] + w:
nodes_prop[v]["distance"] = nodes_prop[u]["distance"] + w
nodes_prop[v]["parent"] = u
return nodes_prop
def dijkstra_pair(graph, start, end):
props = dijkstra(graph, start)
if end in props:
return getPath(props, end)
return None
def getPath(nodes, targetNode):
current = targetNode
path = []
while nodes[current]["parent"]:
path.append(nodes[current]["parent"])
current = nodes[current]["parent"]
return path
Edsger W. Dijkstra - Dutch computer scientist
11/05/1930 - 06/08/2002
How would you calculate shortest paths for all pairs?
In graph theory, betweenness centrality is a measure of centrality in a graph based on shortest paths.
\[ g(v) = \sum{\frac{\sigma_{st}(v)}{\sigma_{st}}} \] where \(\sigma_{st}\) is the total number of shortest paths from node s to not t and \(\sigma_{st}(v)\) is the number of those paths that pass through \(v\). image source
In a connected graph, the normalized closeness centrality (or closeness) of a node is the average length of the shortest path between the node and all other nodes in the graph.
\[ C(x) = \frac{1}{\sum_yd(y,x)} \] where \(d(y,x)\) is the distance between vertices \(x\) and \(y\).
How to identify communities in social media?
A connected component of an undirected graph is a subgraph in which any two nodes are connected to each other by paths, and which is connected to no additional vertices in the supergraph.
Graph with 2 components
Running a search algorithm (BFS or DFS) with a given start node we find only 1 connected component.
Looping through nodes which where not visited yet and running a search algorithm for them, can help to find all connected components in linear time O(|V| + |E|).
A directed graph is called strongly connected if there is a path in each direction between each pair of vertices of the graph.
For a directed graph:
How to schedule lectures some of which depend on others?
Telecom company tries to lay cable in a neighborhood. How to decide where to bury the cable to make sure all the houses are connected?
A subset of the edges of a connected, edge-weighed undirected graph that connects all nodes together, without cycles and with the minimum total edge weight.
How to rank webpages and build a search engine?
PR(node) = sum(PR(node.neigbor)/DegreeOut(node.neighbor))
PR(node) = sum(PR(node.neigbor)/DegreeOut(node.neighbor))
def pagerank(graph, damping=0.85, epsilon=1.0e-8):
inlink_map = {}
outlink_counts = {}
def new_node(node):
if node not in inlink_map: inlink_map[node] = set()
if node not in outlink_counts: outlink_counts[node] = 0
for tail_node, head_node in graph:
new_node(tail_node)
new_node(head_node)
if tail_node == head_node: continue
if tail_node not in inlink_map[head_node]:
inlink_map[head_node].add(tail_node)
outlink_counts[tail_node] += 1
all_nodes = set(inlink_map.keys())
for node, outlink_count in outlink_counts.items():
if outlink_count == 0:
outlink_counts[node] = len(all_nodes)
for l_node in all_nodes: inlink_map[l_node].add(node)
initial_value = 1 / len(all_nodes)
ranks = {}
for node in inlink_map.keys(): ranks[node] = initial_value
new_ranks = {}
delta = 1.0
n_iterations = 0
while delta > epsilon:
new_ranks = {}
for node, inlinks in inlink_map.items():
new_ranks[node] = ((1 - damping) / len(all_nodes)) + (damping * sum(ranks[inlink] / outlink_counts[inlink] for inlink in inlinks))
delta = sum(abs(new_ranks[node] - ranks[node]) for node in new_ranks.keys())
ranks, new_ranks = new_ranks, ranks
n_iterations += 1
return ranks, n_iterations