From 14e13f42246551662f077ef1d2c72c9d7794a501 Mon Sep 17 00:00:00 2001 From: James Sherratt Date: Mon, 21 Oct 2019 01:10:54 +0100 Subject: [PATCH] Added graphs python code Added python script which demnostrates a graph data structure, with some basic methods (operators). --- graphing/graph.py | 122 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 graphing/graph.py diff --git a/graphing/graph.py b/graphing/graph.py new file mode 100644 index 0000000..f4c6efa --- /dev/null +++ b/graphing/graph.py @@ -0,0 +1,122 @@ +""" +:Author: James Sherratt +:Date: 20/10/2019 +:License: MIT + +:name: graph.py +""" + + +class Graph: + + def __init__(self): + self.vertices = set() + self.edges = set() + + def add_vertex(self, vert): + """ + Add a vertex to the graph. + + :param vert: name of the vertex. + :return: None + """ + self.vertices.add(vert) + + def add_edge(self, vert1, vert2, directional=False): + """ + Add an edge to the graph. The edge will be defined as a simple tuple where: + - The first value is the initial edge. + - The second is the final edge. + - The third is whether the edge is directional. + + :param vert1: the start vertex. + :param vert2: the end vertex. + :param directional: whether or not the edge has a direction. Default: False + :return: None + """ + self.vertices.add(vert1) + self.vertices.add(vert2) + if (not directional) and (vert1 > vert2): + # swap if not directional to avoid duplicates in the set. + self.edges.add((vert2, vert1, directional)) + else: + self.edges.add((vert1, vert2, directional)) + + def adjacency(self, vert1, vert2): + """ + Check if 2 vertices are adjacent (if they exist). Note: if vert1 and vert2 + are connected, but directionally from vert2 to vert1, False is returned. + + :param vert1: The first vertex to compare. + :param vert2: The second vertex to compare. + :return: True if adjacent, False if not, None if either are not in the set. + """ + if (vert1 not in self.vertices) or (vert2 not in self.vertices): + return None + + for edge in self.edges: + if (vert1 == edge[0]) and (vert2 == edge[1]): + return True + if (not edge[2]) and ((vert1 == edge[1]) and (vert2 == edge[0])): + return True + return False + + def neighbours(self, vert): + """ + Get the neighbours of a vertex. + :param vert: name of the vertex. + :return: list of neighbours, or None if the vertex is not in the graph. + """ + if vert not in self.vertices: + return None + + neighbours = set() + for edge in self.edges: + if vert == edge[0]: + neighbours.add(edge[1]) + elif (not edge[2]) and (vert == edge[1]): + neighbours.add(edge[0]) + return neighbours + + def as_dict(self): + """ + Convert the graph to a dictionary where: + - Each key is a vertex. + - Each value is a set of neighbours you can travel to. + + :return: dict representing the graph. + """ + graph_dict = {v: set() for v in self.vertices} + for edge in self.edges: + graph_dict[edge[0]].add(edge[1]) + if not edge[2]: + graph_dict[edge[1]].add(edge[0]) + + return graph_dict + + +if __name__ == "__main__": + mygraph = Graph() + mygraph.add_edge("a", "b") + mygraph.add_edge("b", "c") + mygraph.add_edge("b", "d") + mygraph.add_edge("c", "b") + mygraph.add_edge("a", "e", directional=True) + mygraph.add_vertex("z") + print("b neighbours:", mygraph.neighbours("b")) + print("a neighbours:", mygraph.neighbours("a")) + print("q neighbours:", mygraph.neighbours("q")) + print("e neighbours:", mygraph.neighbours("e")) + print() + # Adjacency has direction. + print("a and e adjacent:", mygraph.adjacency("a", "e")) + print("e and a adjacent:", mygraph.adjacency("e", "a")) + print("d and b adjacent", mygraph.adjacency("d", "b")) + print("q and a adjacent:", mygraph.adjacency("q", "a")) + print("z and a adjacent:", mygraph.adjacency("z", "a")) + print() + print("as dict") + print(mygraph.as_dict()) + + # Exercise/ project: add a method "path" to find path between 2 vertices. + # (Hint: lookup DFS/ BFS algorithm.)