Предположим, у меня есть дерево в виде списка смежности
Важно (для вашего понимания) отметить, что у вас есть связанный граф в этом виде списка смежности, но я думаю, что это была просто опечатка. Я предложу это как редактирование, но я просто хочу, чтобы вы знали об этом.
То, что это график, а не дерево, видно из этих строк:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
Здесь у вас уже есть круг на A-B-I:
A
12/_\25
B 8 I
Наличие круга по определению означает, что оно не может быть деревом!
Есть еще одна вещь, которую можно увидеть по тому, как я представил этот подграф:
ребра имеют вес, а не узлы.
Теперь давайте посмотрим на предоставленный вами пример:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
Прежде всего, мы видим, что этот список смежности либо неверен, либо уже оптимизирован для ваших нужд. Это можно (например) увидеть по линиям
E 2 F 60 G 38
F 0
В первой строке показано ребро от E до F, но во второй строке указано, что F имеет степень 0, но эта степень определяется ребрами, падающими на него!
Вот как будет выглядеть список смежности, если он будет «завершен»:
A 2 B 12 I 25
B 4 A 12 C 10 H 40 I 8
C 3 B 10 D 18 G 55
D 2 C 18 E 44
E 3 D 44 F 60 G 38
F 1 E 60
G 3 C 55 E 38 H 35
H 3 B 40 G 35 I 35
Мы можем видеть много избыточности, потому что каждое ребро встречается дважды, поэтому ваш «оптимизированный» список смежности лучше соответствует вашим потребностям - будь это «полный» пример, можно было бы сделать много бесполезных проверок.
Однако вы должны только полагаться на это, если вы можете быть уверены, что все данные, переданные вашему коду, уже «оптимизированы» (или, скорее, в этом формате)! Теперь я буду принимать это как данность.
Давайте поговорим о вашей структуре данных.
Конечно, вы можете использовать предложенный массив строк, но, если честно, я бы рекомендовал что-то вроде предложенной структуры данных @ AmirAfghani. Использование его подхода сделало бы вашу работу проще (поскольку - как он уже указывал - было бы ближе к вашему умственному представлению ) и даже более эффективным (я полагаю, не полагайтесь на это предположение;)) в противном случае вы выполняете много операций со строками.
В названии, которое вы спросили по алгоритму Прима, но в своем реальном вопросе вы сказали или Прима или Крускала. Я пойду с Крускалом просто потому, что его алгоритм намного проще, и вы, кажется, принимаете оба.
алгоритм Крускала
Алгоритм Крускала довольно прост, он в основном:
- Начните с каждого узла, но без ребер
Повторяйте как можно чаще:
- Из всех неиспользованных / не выбранных ребер выберите тот, который имеет наименьший вес (если их больше одного: просто выберите один из них)
- Проверьте, не вызовет ли этот край круг, если это так, отметьте его как выбранный и «отбросьте» его.
- Если круг не вызывает, используйте его и пометьте как использованный / выбранный.
Вот и все. Это действительно так просто.
Тем не менее, я хотел бы упомянуть одну вещь в этом пункте, я думаю, что это лучше всего подходит здесь: вообще не существует «минимального остовного дерева», а «минимального остовного дерева», поскольку их может быть много, поэтому ваши результаты могут отличаться!
Вернуться к вашей структуре данных! Теперь вы можете понять, почему было бы плохой идеей использовать массив строк в качестве структуры данных. Вы бы повторили много операций со строками (например, проверяя вес каждого ребра), и строки являются неизменяемыми , что означает, что вы не можете просто «выбросить» один из ребер или отметить один краев любым способом.
Используя другой подход, вы можете просто установить вес -1, или даже удалить запись для края!
Поиск в глубину
Из того, что я видел, я думаю, что ваша главная проблема - решить, будет ли ребро причиной круга или нет, верно?
Чтобы решить это, вам, вероятно, придется вызвать алгоритм поиска в глубину и использовать его возвращаемое значение.Основная идея заключается в следующем: начать с одного из узлов (я назову этот узел корнем) и попытаться найти путь к узлу на другом конце выбранного ребра (я назову этот узел целевым узлом).(конечно, на графике, у которого еще нет этого края)
- Выберите один не посещенный край, инцидентный с вашим корнем
- Пометить этот выбранный край как посещенный (или что-то подобноекак хотите)
- повторите два последних шага для узла на другой стороне посещенного края
- всякий раз, когда нет невидимых ребер, вернитесь на один край назад
- , есливы вернулись к своему корню и у вас не осталось никаких невидимых краев, все готово.верните false.
- если вы в любой момент заходите на целевой узел, все готово.верните истину.
Теперь, если этот метод возвращает true
, это ребро вызовет круг.