Предложения простейших алгоритмов для некоторых графовых операций - PullRequest
8 голосов
/ 15 апреля 2010

Крайний срок для этого проекта приближается очень быстро, и у меня не так много времени, чтобы разобраться с тем, что у него осталось. Поэтому вместо того, чтобы искать лучшие (и, вероятно, более сложные / трудоемкие) алгоритмы, я ищу самые простые алгоритмы для реализации нескольких операций над структурой Graph.

Операции, которые мне нужно сделать, следующие:

  • Список всех пользователей в сети графа с указанным расстоянием X
  • Список всех пользователей в сети графа с указанием расстояния X и типа отношения
  • Рассчитать кратчайший путь между двумя пользователями в сети графа с учетом типа отношения
  • Рассчитать максимальное расстояние между двумя пользователями в сети графа
  • Подсчет самых удаленных подключенных пользователей в сети графа

Несколько замечаний о моей реализации Graph:

  • Краевой узел имеет 2 свойства: одно имеет тип char, а другое int. Они представляют тип отношения и вес соответственно.
  • График реализован со связанными списками, как для вершин, так и для ребер. Я имею в виду, что каждая вершина указывает на следующую, и каждая вершина также указывает на заголовок другого связанного списка, ребра для этой конкретной вершины.

Что я знаю о том, что мне нужно делать:

  • Я не знаю, является ли это самым простым, как я сказал выше, но для кратчайшего пути между двумя пользователями, я считаю, что алгоритм Дейкстры - это то, что люди, кажется, рекомендуют довольно часто, поэтому я думаю, что я иду с этим.
    • Я искал и искал, и мне трудно реализовать этот алгоритм, кто-нибудь знает какой-нибудь учебник или что-то простое для понимания, чтобы я мог реализовать этот алгоритм сам? Если это возможно, с примерами исходного кода на C, это очень поможет. Я вижу много примеров с математическими обозначениями, но это еще больше смущает меня.
    • Как вы думаете, было бы полезно, если бы я "преобразовал" график в матрицу смежности для представления веса ссылок и типа отношений? Будет ли проще выполнить алгоритм на этом, а не на связанных списках? Я мог бы легко реализовать функцию, чтобы сделать это преобразование при необходимости. Я говорю это, потому что у меня сложилось ощущение, что будет легче после прочтения нескольких страниц на эту тему, но я могу ошибаться.
  • У меня нет идей о других 4 операциях, предложениях?

Ответы [ 3 ]

8 голосов
/ 15 апреля 2010

Список всех пользователей в сети графа с указанным расстоянием X

Расстояние X от чего? от стартового узла или расстояние X между собой? Можете привести пример? Это может быть или не быть так просто, как поиск BF или запуск Dijkstra.

Предполагая, что вы начинаете с определенного узла и хотите перечислить все узлы, которые имеют расстояния X до начального узла, просто запустите BFS от начального узла. Когда вы собираетесь вставить новый узел в очередь, убедитесь, что расстояние от начального узла до узла, с которого вы хотите вставить новый узел, + вес ребра от узла, с которого вы хотите вставить новый узел, до новый узел <= <code>X. Если он строго ниже, вставьте новый узел и, если он равен, просто распечатайте новый узел (и вставьте его только в том случае, если в качестве веса ребра также можно указать 0).

Список всех пользователей в сети графа с указанием расстояния X и типа отношения

Смотри выше. Просто укажите тип отношения в BFS: если тип родителя отличается от типа узла, который вы пытаетесь вставить в очередь, не вставляйте его.

Рассчитать кратчайший путь между двумя пользователями в сети графа с учетом типа отношения

Алгоритм зависит от ряда факторов:

  • Как часто вам нужно будет это вычислять?
  • Сколько у вас узлов?

Поскольку вы хотите легкого, самые легкие - это Рой-Флойд и Дейкстра.

  • Использование Roy-Floyd является кубическим по количеству узлов, поэтому неэффективно. Используйте это только в том случае, если вы можете позволить себе запустить его один раз, а затем ответить на каждый запрос в O (1). Используйте это, если вы можете позволить себе сохранить матрицу смежности в памяти.
  • Число Дейкстры является квадратичным по числу узлов, если вы хотите, чтобы оно было простым, но вам придется запускать его каждый раз, когда вы хотите рассчитать расстояние между двумя узлами. Если вы хотите использовать Dijkstra's, используйте список смежности.

Вот реализации C: Рой-Флойд и Dijkstra_1 , Dijkstra_2 . Вы можете найти много на Google с "<algorithm name> c implementation".

Редактировать: Рой-Флойд исключен для 18 000 узлов, как и матрица смежности. Это займет слишком много времени, чтобы построить и слишком много памяти. Лучше всего либо использовать алгоритм Дейкстры для каждого запроса, но предпочтительно реализовать Дейкстру, используя кучу - в приведенных мною ссылках используйте кучу, чтобы найти минимум. Если вы запускаете классическую Dijkstra для каждого запроса, это также может занять очень много времени.

Другим вариантом является использование алгоритма Bellman-Ford для каждого запроса, что даст вам O(Nodes*Edges) время выполнения для каждого запроса. Тем не менее, это большая переоценка, если вы не реализуете это, как вам говорит Википедия. Вместо этого используйте очередь, аналогичную той, которая используется в BFS. Всякий раз, когда узел обновляет свое расстояние от источника, вставьте этот узел обратно в очередь. Это будет очень быстро на практике, а также будет работать для отрицательных весов. Я предлагаю вам использовать эту или Dijkstra с кучей, поскольку классическая Dijkstra может занять много времени на 18 000 узлов.

Рассчитать максимальное расстояние между двумя пользователями в сети графа

Самый простой способ - это вернуться назад: попробуйте все возможности и сохраните самый длинный путь. Это NP-полная , поэтому полиномиальных решений не существует.

Это действительно плохо, если у вас 18 000 узлов, я не знаю ни одного алгоритма (простого или нет), который бы работал достаточно быстро для такого количества узлов. Попробуйте аппроксимировать его, используя жадные алгоритмы. Или, возможно, ваш график имеет определенные свойства, которыми вы могли бы воспользоваться. Например, это DAG (направленный ациклический граф)?

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

То есть вы хотите найти диаметр графика. Самый простой способ сделать это - найти расстояния между каждыми двумя узлами (во всех парах кратчайшие пути - либо запустить Roy-Floyd или Dijkstra между каждыми двумя узлами и выбрать два с максимальным расстоянием).

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

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

Нет, матрица смежности и Рой-Флойд - очень плохая идея, если ваше приложение не предназначено для суперкомпьютеров.

5 голосов
/ 15 апреля 2010

Предполагается, что O(E log V) является приемлемым временем работы, если вы делаете что-то в сети, это может быть не так, и для этого потребуется более мощное оборудование.

  • Список всех пользователей в сети графа с указанным расстоянием X

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

  • Список всех пользователей в сети графа с указанием расстояния X и типа отношения

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

  • Рассчитать кратчайший путь между двумя пользователями в сети графа, учитывая тип отношения

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

  • Рассчитать максимальное расстояние между двумя пользователями в сети графа

Самый длинный путь - это NP-полная проблема .

  • Подсчет самых удаленных подключенных пользователей в сети графа

Это диаметр графика, о котором вы можете прочитать на Math World .

Что касается списка смежности и вопроса о матрице смежности, то это зависит от того, насколько плотно заполнен ваш граф. Кроме того, если вы хотите кешировать результаты, то вам может пригодиться матрица.

1 голос
/ 15 апреля 2010

Самым простым алгоритмом для вычисления кратчайшего пути между двумя узлами является Floyd-Warshall . Это просто тройное гнездо для циклов; это все.

Он вычисляет ALL -пары кратчайшего пути в O(N^3), поэтому он может выполнить больше работы, чем необходимо, и займет некоторое время, если N огромен.

...