one-file-projects/graph.py

167 lines
3.8 KiB
Python

#!/usr/bin/env python
class Infinity:
def __eq__(self,other):
return isinstance(other,Infinity)
def __gt__(self,other):
return not isinstance(other, Infinity)
def __lt__(self,other):
return False
def __add__(self,other):
return self
def __radd__(self,other):
return self
def __repr__(self):
return "inf"
class Graph:
def __init__(self):
self.nodes = set()
self.edges = set()
def add_node(self,node):
self.nodes.add(node)
def add_edge(self,nodefrom, nodeto, extra=None, both=False):
self.require_node(nodefrom)
self.require_node(nodeto)
self.edges.add( (nodefrom,nodeto,extra) )
if both:
self.add_edge(nodeto, nodefrom, extra=extra, both=False)
def all_edges_of(self,nodefrom):
return filter(lambda e: e[0] == nodefrom, self.edges)
def has_node(self, node):
return node in self.nodes
def require_node(self,node):
if not self.has_node(node):
raise Exception("Node %s does not exist" % repr(node))
def dijkstra(graph,startnode):
graph.require_node(startnode)
d = { node: Infinity() for node in graph.nodes }
d[startnode] = 0
V = [startnode]
while len(V) > 0:
node = min(V, key=lambda e: d[e])
V.remove(node)
for _, neighbor, distance in graph.all_edges_of(node):
if d[neighbor] > d[node] + distance:
d[neighbor] = d[node] + distance
V.append(neighbor)
return d
def bfs(graph, startnode):
graph.require_node(startnode)
visited = set()
not_visited = [startnode]
while len(not_visited) > 0:
node = not_visited.pop(0)
yield node
visited.add(node)
for _, neighbor, extra in graph.all_edges_of(node):
if neighbor not in visited and neighbor not in not_visited:
not_visited.append(neighbor)
def dfs(graph, node, visited=None):
graph.require_node(node)
if visited is None:
visited = []
yield node
visited.append(node)
for _, neighbor, extra in graph.all_edges_of(node):
if neighbor not in visited:
for node in dfs(graph, neighbor, visited=visited):
yield node
def prim(graph,r=None):
if r is None:
r = list(graph.nodes)[0]
Vt = set();
Vt.add(r);
d = { node: Infinity() for node in graph.nodes }
d[r] = 0;
for _, neighbor, distance in graph.all_edges_of(r):
d[neighbor] = distance
while Vt < graph.nodes:
u = min(graph.nodes - Vt, key=lambda node: d[node])
if d[u] == Infinity():
break
Vt.add(u)
for _, neighbor, distance in graph.all_edges_of(u):
if neighbor not in Vt:
d[neighbor] = min([ d[neighbor], distance ])
return d;
def main():
g = Graph()
for i in range(1,6):
g.add_node(i)
g.add_edge(1,2,10)
g.add_edge(1,4,30)
g.add_edge(1,5,100)
g.add_edge(2,3,50)
g.add_edge(3,5,10)
g.add_edge(4,3,20)
g.add_edge(4,5,60)
d = dijkstra(g,1)
print(d)
d = prim(g)
print(d)
print( list(bfs(g,1)) )
print( list(dfs(g,1)) )
g2 = Graph()
for i in range(1,10):
g2.add_node(i)
for i in range(1,5):
g2.add_edge(i,2*i)
g2.add_edge(i,2*i+1)
print( list(bfs(g2,1)) )
print( list(dfs(g2,1)) )
g3 = Graph()
g3.add_node(1)
g3.add_node(2)
g3.add_node(3)
g3.add_node(4)
g3.add_node(5)
g3.add_node(6)
g3.add_edge(1,2,20)
g3.add_edge(1,3,10)
g3.add_edge(2,4,30)
g3.add_edge(2,5,20)
g3.add_edge(3,4,10)
g3.add_edge(3,5,20)
g3.add_edge(4,6,10)
g3.add_edge(5,6,30)
d = prim(g3,1)
print(d)
if __name__ == '__main__':
main()