|
| 1 | +class Graph: |
| 2 | + def __init__(self): |
| 3 | + # dictionary containing keys that map to the corresponding vertex object |
| 4 | + self.vertices = {} |
| 5 | + |
| 6 | + def add_vertex(self, key): |
| 7 | + """Add a vertex with the given key to the graph.""" |
| 8 | + vertex = Vertex(key) |
| 9 | + self.vertices[key] = vertex |
| 10 | + |
| 11 | + def get_vertex(self, key): |
| 12 | + """Return vertex object with the corresponding key.""" |
| 13 | + return self.vertices[key] |
| 14 | + |
| 15 | + def __contains__(self, key): |
| 16 | + return key in self.vertices |
| 17 | + |
| 18 | + def add_edge(self, src_key, dest_key, weight=1): |
| 19 | + """Add edge from src_key to dest_key with given weight.""" |
| 20 | + self.vertices[src_key].add_neighbour(self.vertices[dest_key], weight) |
| 21 | + |
| 22 | + def does_edge_exist(self, src_key, dest_key): |
| 23 | + """Return True if there is an edge from src_key to dest_key.""" |
| 24 | + return self.vertices[src_key].does_it_point_to(self.vertices[dest_key]) |
| 25 | + |
| 26 | + def __len__(self): |
| 27 | + return len(self.vertices) |
| 28 | + |
| 29 | + def __iter__(self): |
| 30 | + return iter(self.vertices.values()) |
| 31 | + |
| 32 | + |
| 33 | +class Vertex: |
| 34 | + def __init__(self, key): |
| 35 | + self.key = key |
| 36 | + self.points_to = {} |
| 37 | + |
| 38 | + def get_key(self): |
| 39 | + """Return key corresponding to this vertex object.""" |
| 40 | + return self.key |
| 41 | + |
| 42 | + def add_neighbour(self, dest, weight): |
| 43 | + """Make this vertex point to dest with given edge weight.""" |
| 44 | + self.points_to[dest] = weight |
| 45 | + |
| 46 | + def get_neighbours(self): |
| 47 | + """Return all vertices pointed to by this vertex.""" |
| 48 | + return self.points_to.keys() |
| 49 | + |
| 50 | + def get_weight(self, dest): |
| 51 | + """Get weight of edge from this vertex to dest.""" |
| 52 | + return self.points_to[dest] |
| 53 | + |
| 54 | + def does_it_point_to(self, dest): |
| 55 | + """Return True if this vertex points to dest.""" |
| 56 | + return dest in self.points_to |
| 57 | + |
| 58 | + |
| 59 | +def bellman_ford(g, source): |
| 60 | + """Return distance where distance[v] is min distance from source to v. |
| 61 | + |
| 62 | + This will return a dictionary distance. |
| 63 | + |
| 64 | + g is a Graph object which can have negative edge weights. |
| 65 | + source is a Vertex object in g. |
| 66 | + """ |
| 67 | + distance = dict.fromkeys(g, float('inf')) |
| 68 | + distance[source] = 0 |
| 69 | + |
| 70 | + for _ in range(len(g) - 1): |
| 71 | + for v in g: |
| 72 | + for n in v.get_neighbours(): |
| 73 | + distance[n] = min(distance[n], distance[v] + v.get_weight(n)) |
| 74 | + |
| 75 | + return distance |
| 76 | + |
| 77 | + |
| 78 | +g = Graph() |
| 79 | +print('Menu') |
| 80 | +print('add vertex <key>') |
| 81 | +print('add edge <src> <dest> <weight>') |
| 82 | +print('bellman-ford <source vertex key>') |
| 83 | +print('display') |
| 84 | +print('quit') |
| 85 | + |
| 86 | +while True: |
| 87 | + do = input('What would you like to do? ').split() |
| 88 | + |
| 89 | + operation = do[0] |
| 90 | + if operation == 'add': |
| 91 | + suboperation = do[1] |
| 92 | + if suboperation == 'vertex': |
| 93 | + key = int(do[2]) |
| 94 | + if key not in g: |
| 95 | + g.add_vertex(key) |
| 96 | + else: |
| 97 | + print('Vertex already exists.') |
| 98 | + elif suboperation == 'edge': |
| 99 | + src = int(do[2]) |
| 100 | + dest = int(do[3]) |
| 101 | + weight = int(do[4]) |
| 102 | + if src not in g: |
| 103 | + print('Vertex {} does not exist.'.format(src)) |
| 104 | + elif dest not in g: |
| 105 | + print('Vertex {} does not exist.'.format(dest)) |
| 106 | + else: |
| 107 | + if not g.does_edge_exist(src, dest): |
| 108 | + g.add_edge(src, dest, weight) |
| 109 | + else: |
| 110 | + print('Edge already exists.') |
| 111 | + |
| 112 | + elif operation == 'bellman-ford': |
| 113 | + key = int(do[1]) |
| 114 | + source = g.get_vertex(key) |
| 115 | + distance = bellman_ford(g, source) |
| 116 | + print('Distances from {}: '.format(key)) |
| 117 | + for v in distance: |
| 118 | + print('Distance to {}: {}'.format(v.get_key(), distance[v])) |
| 119 | + print() |
| 120 | + |
| 121 | + elif operation == 'display': |
| 122 | + print('Vertices: ', end='') |
| 123 | + for v in g: |
| 124 | + print(v.get_key(), end=' ') |
| 125 | + print() |
| 126 | + |
| 127 | + print('Edges: ') |
| 128 | + for v in g: |
| 129 | + for dest in v.get_neighbours(): |
| 130 | + w = v.get_weight(dest) |
| 131 | + print('(src={}, dest={}, weight={}) '.format(v.get_key(), |
| 132 | + dest.get_key(), w)) |
| 133 | + print() |
| 134 | + |
| 135 | + elif operation == 'quit': |
| 136 | + break |
0 commit comments