""" graph_april12.py in class April 12 $ python graph_april12.py -- depth-first search A C G F B E K J D I H -- breadth-first search A B C D E F G H I J K """ a='A'; b='B'; c='C'; d='D'; e='E'; f='F'; g='G'; h='H'; i='I'; j='J'; k='K' # each pair is (parent, child) in the tree edges_1 = ( (a, b), (a, c), (b, d), (b, e), (c, f), (c, g), (d, h), (d, i), (e, j), (e, k) ) def neighbors_of(vertex, edges): """ Given a letter (vertex), return a list of its neighbors """ # This is not an efficient way to get the edges in general ... # it's just something that's easy to do, and for this small # example the speed doesn't matter. result = [] for (v1, v2) in edges: if v1 == vertex: result.append(v2) if v2 == vertex: result.append(v1) return result class Stack: """ first in, last out, with O(1) "x in stack" >>> s = Stack() >>> s.push(1); s.push(2); s.push(3) >>> 1 in s True >>> (s.pop(), s.pop(), s.pop()) (3, 2, 1) >>> len(s) 0 """ def __init__(self): self.values = [] self.has = {} # also put values in a dictionary def __len__(self): return len(self.values) def __contains__(self, value): # implement the "_ in _" python syntax. return value in self.has def push(self, value): self.values.append(value) self.has[value] = True def pop(self): value = self.values.pop() self.has.pop(value) # remove from dictionary return value class Queue(Stack): """ first in, first out >>> q = Queue() >>> q.push(1); q.push(2); q.push(3) >>> 5 in q False >>> (q.pop(), q.pop(), q.pop()) (1, 2, 3) >>> len(q) 0 """ def pop(self): value = self.values.pop(0) self.has.pop(value) return value def search(start, which, edges, function): """ depth-first or breadth-first search """ visited = {} # Nodes which we're done with. if which == 'depth': # Create a fringe of nodes-to-visit ... fringe = Stack() # ... either a stack else: fringe = Queue() # ... or a queue. fringe.push(start) # Initialize the search. while len(fringe) > 0: # Search loop: node = fringe.pop() # Get node to process. visited[node] = True # Mark it as 'processed'. function(node) # Do something with it. neighbors = neighbors_of(node, edges) # Get its neighbors for candidate in neighbors: # Add new ones to fringe. if not candidate in visited and not candidate in fringe: fringe.push(candidate) def main(): print(' -- depth-first search ') search(a, 'depth', edges_1, print) print(' -- breadth-first search ') search(a, 'breadth', edges_1, print) if __name__ == '__main__': main()