Нахождение всех несвязных подграфов в графе

У меня есть граф, который содержит неизвестное количество несвязанных подграфов. Какой хороший алгоритм (или библиотека Java), чтобы найти их все?


person Ollie Glass    schedule 28.08.2009    source источник
comment
Всем спасибо, особенно МАКу и Агору. Я собираюсь начать с заливки и поиска в ширину, а затем продолжить оттуда.   -  person Ollie Glass    schedule 29.08.2009


Ответы (7)


Я думаю, что то, что вы ищете, обычно называется Flood Fill. Вам решать, проходите ли вы граф через BFS или DFS.

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

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

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

person MAK    schedule 28.08.2009
comment
Спасибо, это отличное место для начала и очень практичный ответ. - person Ollie Glass; 29.08.2009

Не Java-реализация, но, возможно, кому-то будет полезно, вот как это сделать на Python:

import networkx as nx
g = nx.Graph()
# add nodes/edges to graph

d = list(nx.connected_components(g)) 
# d contains disconnected subgraphs
# d[0] contains the biggest subgraph

Дополнительная информация здесь.

person Datageek    schedule 08.07.2012

Есть много аспектов этого вопроса, которые не полностью объяснены, поэтому я собираюсь дать несколько исчерпывающий ответ. Несмотря на мою склонность публиковать стены текста. :/ Обратите также внимание, что я предполагаю, что это вопрос домашнего задания или вопрос самообразования, поэтому я не собираюсь давать прямой ответ.

Двумя основными алгоритмами обнаружения связности графа являются Поиск в глубину и Поиск в ширину. Это действительно две отправные точки, на которые вы хотите обратить внимание. Оба приведут вас к решению, но по-разному, и трудно спорить, что «лучше», не рассматривая некоторые довольно глубокие аспекты проблемы. Но давайте двигаться дальше.

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

Является ли ваш граф направленным или неориентированным? и считаете ли вы связность в «сильном» смысле (в этом случае см. ответ oggy) или связность в «слабом» смысле? В зависимости от вашего ответа вам придется подходить к своему алгоритму немного по-другому. Обратите внимание, что для неориентированного графа слабая и сильная связность эквивалентны, так что это хорошо. Но вам все равно придется помнить о структуре графа при реализации или поиске алгоритма.

Кроме того, возникает вопрос о том, что вы подразумеваете под «нахождением подграфов» (парафраз). Обычно связность графа является проблемой решения — просто «есть один связанный граф» или «есть два или более подграфа (он же несвязанный)». Наличие алгоритма для этого требует наименьшего количества книжной работы, и это приятно. :) Следующим шагом будет количество графиков, буквально их количество, и эта книжная работа тоже не так уж и плоха. Наконец, вам может понадобиться список узлов в каждом подграфе. Наконец, вы можете буквально скопировать подграфы, ребра и все остальное (поэтому возвращаемый тип будет списком графов, я полагаю, с подразумеваемым инвариантом, что каждый граф связан). Ни один из этих различных типов результатов не требует другого алгоритма, но обязательно потребует другого подхода к работе с книгами.

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

person agorenst    schedule 28.08.2009
comment
Спасибо, это вопрос самообразования, и я ценю детали, я ценю то, что вы проливаете свет на сделанные мной предположения. Я работаю с неориентированными графами, и моя цель создать метод, который берет один граф и возвращает набор всех подграфов. - person Ollie Glass; 29.08.2009

JGraphT — это хорошая графическая библиотека с открытым исходным кодом, распространяемая под лицензией LGPL. Я использовал его в прошлом для работы с графиками и обнаружения циклов на графиках. Он также довольно прост в использовании, и вы можете использовать JGraph для визуализации графиков.

person aperkins    schedule 28.08.2009
comment
Класс ConnectivityInspector должен быть тем, что нужно. - person serg; 29.08.2009
comment
Поскольку мне никогда не приходилось делать ничего, кроме доказательства существования/отсутствия циклов, я не был уверен, поэтому я просто подключился к библиотеке - для нашего проекта это было довольно солидно. - person aperkins; 29.08.2009

Я предполагаю, что вы хотите найти все (сильно) связанные компоненты? Для этого вы можете использовать алгоритм Тарьяна (вариант DFS)

person oggy    schedule 28.08.2009

Как насчет поиска в ширину, чтобы найти все связанные узлы? Получив список подключенных узлов, вы вычитаете этот список из списка всех узлов. В итоге вы получите список отключенных узлов

person MedicineMan    schedule 28.08.2009
comment
Вау, это было именно то, что мне было нужно. Это самый быстрый способ, если вас не интересует конкретная сегментация подграфов и т. д. Вопрос только в том, где начать поиск в графе, но это зависит от конкретного графа c. - person SumakuTension; 06.05.2020

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

person harschware    schedule 08.03.2010