Graf będzie słownikiem, w którym kluczami będą wierzchołki (liczby, napisy, itp.). Każdemu kluczowi będzie odpowiadać lista krotek, zawierająca wierzchołki połączone krawędzią z danym wierzchołkiem, oraz wagi krawędzi prowadzących do danego wierzchołka. Pusty graf będzie reprezentowany przez pusty słownik. W podanej implementacji graf nieskierowany możemy potraktować jak graf skierowany, ale nie na odwrót. Dlatego tam, gdzie to jest istotne, będziemy zaznaczać, że graf jest nieskierowany.
PRZYKŁAD. Rozważmy graf skierowany o wierzchołkach od A do F i krawędziach (A, B, 1), (A, C, 2), (B, C, 3), (B, D, 4), (C, D, 5), (D, C, 6), (E, C, 7). Możemy go zapisać jako słownik.
graph = { "A": [("B", 1), ("C", 2)], "B": [("C", 3), ("D", 4)], "C": [("D", 5)], "D": [("C", 6)], "E": [("C", 7)], "F": []}
Określamy funkcje pomagające we właściwej budowie grafu w Pythonie.
graph = {} # pusty graf (dowolny) directed_graph = {} # pusty graf skierowany undirected_graph = {} # pusty graf nieskierowany
Dodawanie wierzchołka do grafu bez duplikatów.
def add_node(graph, node): """Wstawia wierzchołek do grafu.""" if node not in graph: graph[node] = []
Dodawanie krawędzi do grafu skierowanego bez duplikatów. Na początku próbujemy uzupełniać brakujące wierzchołki. Następnie uzupełniamy listę sąsiedztwa. Krawędź grafu przedstawiamy jako 3-krotkę.
def add_edge_directed(graph, edge): """Dodaje krawędź do grafu skierowanego.""" source, target, weight = edge add_node(graph, source) add_node(graph, target) # Możemy wykluczyć pętle. if source == target: raise ValueError("pętle są zabronione") if (target, weight) not in graph[source]: graph[source].append((target, weight))
Dodawanie krawędzi do grafu nieskierowanego bez duplikatów. Krawędź nieskierowana występuje jako dwie krawędzie skierowane.
def add_edge_undirected(graph, edge): """Dodaje krawędź do grafu nieskierowanego.""" source, target, weight = edge add_node(graph, source) add_node(graph, target) # Możemy wykluczyć pętle. if source == target: raise ValueError("pętle są zabronione") if (target, weight) not in graph[source]: graph[source].append((target, weight)) if (source, weight) not in graph[target]: graph[target].append((source, weight))
Iteracja po wierzchołkach, krawędziach i sąsiadach.
def iternodes(graph): """Zwraca iterator po wierzchołkach grafu.""" #return graph.keys() # Py3 widok na wierzchołki grafu return iter(graph) def iteredges(graph): """Zwraca iterator po krawędziach (3-krotki) grafu skierowanego ważonego.""" for source in graph: for (target, weight) in graph[source]: yield (source, target, weight) def iteradjacent(graph, source): """Zwraca iterator po sąsiadach danego wierzchołka w grafie ważonym.""" for (target, weight) in graph[source]: yield target def print_graph(graph): """Wypisuje postać grafu skierowanego ważonego na ekranie.""" L = [] for source in graph: L.append("{} : ".format(source)) for (target, weight) in graph[source]: L.append("{}({}) ".format(target, weight)) L.append("\n") print("".join(L))