Граф C++ со съемными узлами, доступными свойствами и надежными идентификаторами
Я пытаюсь перейти с проприетарной библиотеки графов на Open Source.
РЕДАКТИРОВАТЬ: так как очень немногие люди, кажется, знают, как на самом деле работает Boost Graph, если вы можете предоставить решение, используя LEMON Graph Library, это тоже хорошо.
В настоящее время мои вершины имеют тип 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, потому что удаление вершины вызывает перенумерацию всех вершин с более высоким ID, а также может привести к перераспределению внутренних структур. Так что до свидания идентификаторы и до свидания указатели.
Главный вопрос Можно ли создать 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
тоже.
Заворачивать. Мне нужен рабочий кусок кода, показывающий, как:
- добавить вершины (со свойствами)
- добавить дуги (со свойствами)
- удалить вершины
- удалить дуги
С этими важными реквизитами:
- возможность индексировать вершины по id (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();
Это может показаться большим количеством вопросов, но на самом деле это просто основа того, что мне нужно для запуска этой библиотеки. Что-нибудь меньшее, и это совершенно бесполезно для того, что мне нужно делать.
Пожалуйста, ударьте все пункты пули.
Думайте об этом как об учебнике, я надеюсь, что предоставление награды поможет и другим людям.
1 ответ
Тогда вместо использования указателей вершин я бы использовал целочисленные индексы вершин.
На самом деле, я думаю, вы бы использовали дескрипторы вершин. Который в случае выбора контейнеров vecS был бы целым, да
Из того, что я понимаю, это не так легко сделать с BGL, потому что удаление вершины вызывает перенумерацию всех вершин с более высоким ID, а также может привести к перераспределению внутренних структур.
Строго говоря, это не всегда так. Это в случае с vecS
но не с например listS
(списки имеют стабильные итераторы).
В общем, я предлагаю посмотреть на listS
в качестве выбора контейнера и отбросить предположение, что vertex_descriptor
быть целочисленным типом (он станет непрозрачным).
В обмен на стабильность итератора вам необходимо предоставить карты вершинных индексов для определенных алгоритмов.