Подтвердить что ты не робот

Представление графиков (структуры данных) в Python

Как можно аккуратно представить graph в Python? (Начиная с нуля, то есть без библиотек!)
Какая структура данных (например, dicts/tuples/dict (кортежи)) будет быстрой, а также эффективной с точки зрения памяти?
Нужно иметь возможность делать различные графики operations на нем.

Как указывалось, различные графические представления могут помочь. Как можно реализовать их в Python?

Что касается библиотек, этот вопрос содержит неплохие ответы.

4b9b3361

Ответ 1

Несмотря на то, что это несколько старый вопрос, я думал, что дам практический ответ, если кто-нибудь споткнутся об этом.

Скажем, вы получаете свои входные данные для своих соединений как список кортежей, например:

[('A', 'B'), ('B', 'C'), ('B', 'D'), ('C', 'D'), ('E', 'F'), ('F', 'C')]

Структура данных, которую я считаю наиболее полезной и эффективной для графиков в Python, представляет собой dict наборов. Это будет основной структурой для нашего класса Graph. Вы также должны знать, являются ли эти соединения дугами (направлены, соединяются в одну сторону) или ребрами (неориентированы, соединяются в обоих направлениях). Мы справимся с этим, добавив параметр directed к методу Graph.__init__. Мы также добавим другие полезные методы.

from collections import defaultdict


class Graph(object):
    """ Graph data structure, undirected by default. """

    def __init__(self, connections, directed=False):
        self._graph = defaultdict(set)
        self._directed = directed
        self.add_connections(connections)

    def add_connections(self, connections):
        """ Add connections (list of tuple pairs) to graph """

        for node1, node2 in connections:
            self.add(node1, node2)

    def add(self, node1, node2):
        """ Add connection between node1 and node2 """

        self._graph[node1].add(node2)
        if not self._directed:
            self._graph[node2].add(node1)

    def remove(self, node):
        """ Remove all references to node """

        for n, cxns in self._graph.iteritems():
            try:
                cxns.remove(node)
            except KeyError:
                pass
        try:
            del self._graph[node]
        except KeyError:
            pass

    def is_connected(self, node1, node2):
        """ Is node1 directly connected to node2 """

        return node1 in self._graph and node2 in self._graph[node1]

    def find_path(self, node1, node2, path=[]):
        """ Find any path between node1 and node2 (may not be shortest) """

        path = path + [node1]
        if node1 == node2:
            return path
        if node1 not in self._graph:
            return None
        for node in self._graph[node1]:
            if node not in path:
                new_path = self.find_path(node, node2, path)
                if new_path:
                    return new_path
        return None

    def __str__(self):
        return '{}({})'.format(self.__class__.__name__, dict(self._graph))

Я оставлю его "упражнением для читателя" для создания find_shortest_path и других методов.

Посмотрим на это, хотя...

>>> connections = [('A', 'B'), ('B', 'C'), ('B', 'D'),
                   ('C', 'D'), ('E', 'F'), ('F', 'C')]
>>> g = Graph(connections, directed=True)
>>> pprint(g._graph)
{'A': {'B'},
 'B': {'D', 'C'},
 'C': {'D'},
 'E': {'F'},
 'F': {'C'}}

>>> g = Graph(connections)  # undirected
>>> pprint(g._graph)
{'A': {'B'},
 'B': {'D', 'A', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'B'},
 'E': {'F'},
 'F': {'E', 'C'}}

>>> g.add('E', 'D')
>>> pprint(g._graph)
{'A': {'B'},
 'B': {'D', 'A', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'E', 'B'},
 'E': {'D', 'F'},
 'F': {'E', 'C'}}

>>> g.remove('A')
>>> pprint(g._graph)
{'B': {'D', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'E', 'B'},
 'E': {'D', 'F'},
 'F': {'E', 'C'}}

>>> g.add('G', 'B')
>>> pprint(g._graph)
{'B': {'D', 'G', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'E', 'B'},
 'E': {'D', 'F'},
 'F': {'E', 'C'},
 'G': {'B'}}

>>> g.find_path('G', 'E')
['G', 'B', 'D', 'C', 'F', 'E']

Ответ 2

NetworkX - это потрясающая библиотека графа Python. Вам будет трудно найти что-то, что вам нужно, чего он еще не делает.

Ответ 3

Во-первых, выбор классических представлений по сравнению с матричными представлениями зависит от цели (о том, что вы хотите сделать с представлением). Известные проблемы и алгоритмы связаны с выбором. Выбор типа абстрактного представления диктует, как он должен быть реализован.

Во-вторых, вопрос заключается в том, должны ли вершины и ребра выражаться только в терминах существования или они несут некоторую дополнительную информацию.

Из встроенной в Python точки данных типа точка зрения любое значение, содержащееся в другом месте, выражается как (скрытая) ссылка на целевой объект. Если это переменная (т.е. Именованная ссылка), то имя и ссылка всегда хранятся во внутреннем словаре. Если вам не нужны имена, ссылка может быть сохранена в вашем собственном контейнере - здесь, вероятно, список Python всегда будет использоваться для списка как абстракция.

Список Python реализуется как динамический массив ссылок, кортеж Python реализуется как статический массив ссылок с постоянным содержимым (значение ссылок не может быть изменено). Из-за этого их можно легко проиндексировать. Таким образом, этот список можно использовать и для реализации матриц.

Другим способом представления матриц являются массивы, реализованные стандартным модулем array - более ограниченным по отношению к сохраненному типу, однородному значению. Элементы хранят значение напрямую. (Вместо этого список сохраняет ссылки на объекты значений). Таким образом, он эффективнее с точки зрения памяти, а также доступ к значению быстрее.

Иногда вы можете найти полезное еще более ограниченное представление, например bytearray.

Ответ 4

Есть две отличные библиотеки графов NetworkX и igraph. Вы можете найти оба исходных кода библиотеки на GitHub. Вы всегда можете увидеть, как записываются функции. Но я предпочитаю NetworkX из-за его легкости понимания.
Посмотрите их коды, как они выполняют функции. Вы получите идею множественности и затем выберите, как вы хотите сделать график, используя структуры данных.