График C++ со съемными узлами, доступными свойствами и надежными идентификаторами

Я пытаюсь мигрировать с проприетарной графической библиотеки на библиотеку с открытым исходным кодом.

РЕДАКТИРОВАТЬ: поскольку так мало людей, похоже, знают, как на самом деле работает Boost Graph, если вы можете предоставить решение с использованием библиотеки LEMON Graph, это тоже хорошо.

В настоящее время мои вершины имеют тип Graph_Vertex* и могут иметь связанный указатель void* для хранения связанной информации. Аналогичная логика используется в отношении ребер, которые имеют тип Graph_Edge*. Я использую указатель void* для хранения собственной структуры Node_State, которая выглядит примерно так:

struct Node_State {
    std::string name;
    int id;
    // other stuff
};

Из того, что я видел в BGL до сих пор, я могу создать граф, используя структуру adjacency_list и связанные свойства, чтобы указать на мой Node_State. Затем, вместо использования указателей вершин, я бы использовал целочисленные индексы вершин.

Я просматривал руководство. и некоторые вопросы здесь, и это кажется возможным. Я думаю о чем-то вроде

typedef adjacency_list < listS, vecS, bidirectionalS, Node_State> gr;

Время от времени я буду удалять все ребра, ведущие к вершине и исходящие из нее. Очень редко я также могу удалить узел. Вот почему я бы выбрал listS, vecS.

Я хотел бы упростить создание второй версии этой структуры для ненаправленных ребер. Я не уверен, что bidirectionalS лучший вариант для моего случая. Ваш вклад приветствуется в этом отношении.

Хотя есть еще одна проблема. Прямо сейчас я могу использовать внешнюю карту для поиска каждой вершины по ее имени или уникальному целочисленному идентификатору.

std::map<int, Graph_Vertex*> nodes_by_id;
std::map<std::string, Graph_Vertex*> nodes_by_name();

Если я удаляю вершину, мне просто нужно удалить соответствующую запись(и) на карте(ах), и все будет продолжать работать.

Насколько я понимаю, этого не так просто добиться с помощью BGL, потому что удаление вершины вызывает перенумерацию всех вершин с более высоким идентификатором, а также может привести к перераспределению внутренних структур. Итак, прощайте идентификаторы и прощайте указатели.

Основной вопрос. Можно ли создать map<name, node> или map<index, node>, которые смогут пережить удаление узла с минимальными изменениями (например, просто удалив неверные ключи)? Если нет, то как лучше всего сопоставить узлы какому-то уникальному идентификатору, сохраняющемуся после изменений в графе?

Вариантом может быть использование внутренние свойства. Учебное пособие пример здесь.

struct vertex_index_t { };
struct edge_index_t { };

struct vertex_name_t { };
struct edge_name_t { };

И сохраняя некоторые внешние структуры

std::map<vertex_index_t, Graph_Vertex*> nodes_by_id;
std::map<vertex_name_t, Graph_Vertex*> nodes_by_name;
std::map<edge_index_t, Graph_Edge*> edges_by_id;
std::map<edge_name_t, Graph_Edge*> edges_by_name;

Это было бы намного больше похоже на то, что у меня есть сейчас, и потребовало бы меньше изменений в текущем коде.

Я не совсем понял, как удаление вершин влияет на vertex_index_t и как можно назначить vertex_name_t. Однако, если это сработает, аналогичная логика может быть применена к краям, используя также edge_index_t и edge_name_t.

Заворачивать. Мне нужен рабочий фрагмент кода, показывающий, как:

  • добавить вершины (со свойствами)
  • добавить дуги (со свойствами)
  • удалить вершины
  • удалить дуги

С этими важными реквизитами:

  • возможность индексировать вершины по идентификатору (int или string), чтобы их было легко получить и получить доступ к их свойствам
  • идентификаторы не должны меняться при удалении вершины
  • добавление индексов и свойств не должно усложнять выполнение таких алгоритмов, как «найти связанные компоненты» и «поиск Дейкстры».

Я был бы счастлив, если бы я мог достичь чего-то вроде

Vertex* vertex0 = Graph.get_vertex_by_name("v0");
Vertex_Data* v0_data = vertex0.get_data();

Edge* edge4 = Graph.get_edge_by_id(4);
Edge_Data* e4_data = edge4.get_data();

Может показаться, что вопросов много, но на самом деле это только основа того, что мне нужно для запуска и работы этой библиотеки. Все, что меньше, и это совершенно бесполезно для того, что мне нужно делать.

Пожалуйста, нажмите все пункты списка.

Думайте об этом как о руководстве, я надеюсь, что щедрость поможет и другим людям.


person Agostino    schedule 17.03.2015    source источник


Ответы (1)


Затем, вместо использования указателей вершин, я бы использовал целочисленные индексы вершин.

На самом деле, я думаю, вы бы использовали дескрипторы вершин. Что в случае выбора контейнера vecS было бы неотъемлемым, да

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

Строго говоря, это не всегда так. Это это случай с vecS, но не с, например. listS (списки имеют стабильные итераторы).

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

В обмен на стабильность итератора вам нужно будет предоставить карты индексов вершин для определенных алгоритмов.

person sehe    schedule 17.03.2015
comment
При использовании listS несколько сложнее предоставить карту vertex_index_t. Вы должны решить, где хранить сопоставление: вершина --› целое число, где целое число должно находиться в интервале [0,num_vertices(g)). Здесь stackoverflow.com/questions/11336723/ это было сделано с использованием свойства вершины. Вы также можете использовать отдельный std::map. В любом случае ключевым элементом является добавление этой специализации шаблона namespace boost { template<> struct property_map<MyGraph, vertex_index_t > {... }; } - person Michael Simbirsky; 18.03.2015
comment
@MichaelSimbirsky большинство алгоритмов принимают необязательный параметр vertex_index (именованный), какова дополнительная ценность использования специализации? - person sehe; 11.04.2015
comment
Совершенно никаких проблем. Я помню наш примерно часовой разговор в чате о графе обучения (среди прочего) . Re: Какие примеры?: В частности, этот комментарий. Для остальных выполните поиск: как предоставить свойство vertex_index для моего графика может помочь, этот показывает, как передать index_map при использовании vecS; - person sehe; 12.04.2015
comment
Спасибо, я восхищен вашим вкладом в StackOverflow и, в частности, в boost-graph. Всегда рад вашим комментариям. Я часто пишу адаптеры, преобразующие существующие структуры в интерфейс Boost.Graph. Например, для простых и двойственных графов диаграммы Вороного Boost.Polygon. Во всех таких случаях я считаю vertex_index естественной частью адаптера. В момент определения графа обычно существует естественная нумерация вершин. Я предпочитаю делать эту нумерацию явной, чтобы избавить пользователя моего кода от необходимости определять свою собственную карту индексов вершин. - person Michael Simbirsky; 13.04.2015