Вопрос:
Является ли сложность DFS различной для направленного и неориентированного графика?
Если да, то направленная сложность графа равна O (V + E), а неориентированная сложность графа - O (E)?, Где E - ребра, а V - вершины?
Если да, то следующий комментарий - объяснение сложности O (V + E) для правильного графика?
/*
* Although this piece looks like it is O(V * E), it is actually O(V + E)
* This is because, for each node, we dont do dfs across the full tree.
* ie
* A -> C
* |
* V
* B
* Here A has a directed edge to B and C.
* This means that when 'Node' == A then 'dfs' code would cost O(E)
* But when the 'node' == B then 'dfs' would cost O(1), since B does not have any outgoing edge
* and when the 'node' == C then 'dfs' would cost O(1), since C does not have any outgoing edge
* This O(E + 1 + 1) = O(E)
* And O(A + B + C) = O(V)
*
*/
for (T node : graph) {
if (dfs(graph, node, visitedNodes, completedNodes)) return true;
}
Короче говоря, сложность DFS как для направленного графика, так и для ненаправленного графика должна быть одинаковой. И кажется, что ваш аргумент в отношении сложности работает только для определенного графика, я привел более общий аргумент ниже для вашей справки.
Для графа G = (V, E) обозначим через n = | V | число вершин графа и m = | E | число ребер графа. Алгоритм DFS задается рекурсивно, как показано ниже:
Mark all vertices as unexplored
DFS(graph G, start vertex s)
- Mark s as explored
- For every edge (s, v):
- If v is unexplored
- DFS(G, v)
Фактически это зависит от базовой структуры данных, которую вы используете для реализации графика.
Матрица смежности представляет собой n-мерную матрицу, где a ij (т.е. запись в i-й строке и j-я) обозначает количество ребер от вершины я до вершины j. В этом случае сложность DFS равна O (n 2).
Список смежности представляет собой набор из n неупорядоченных списков для каждой вершины, каждый список представляет собой набор соседей своей вершины. В этом случае сложность DFS равна O (n + m) (как для направленного, так и неориентированного графика).
Сначала рассмотрим использование списка смежности для представления графа, где список для вершины v состоит из указателей на смежные вершины. Пусть m v обозначает количество ребер, смежных с вершиной v. Из этого следует, что число операций, требуемых для вызова DFS(G, v)
равно 1 + m v (маркировка v как исследованная, а затем цикл по m v ребрам). Заметим, что, начиная с произвольной вершины s, алгоритм DFS вызывается рекурсивно на каждую вершину не чаще одного раза (когда вершина не исследована), поэтому общая требуемая работа не более:
Σ v ∈ V (1 + m v) = | V | + Σ v ∈ V m v
В ориентированном графе мы имеем Σ v ∈ V m v= | E |, тогда как в неориентированном графе имеем Σ v ∈ V m v= 2 | E | (это потому, что (u, v) и (v, u) рассматриваются как одно и то же ребро в неориентированном графе). В обоих случаях требуется общая работа O (| V | + | E |) = O (n + m).
Если мы используем матрицу смежности для представления графика, алгоритм DFS также будет рекурсивно вызываться не более одного раза для каждой вершины. Однако, если мы хотим в этом случае перебрать все исходящие ребра вершины v, мы должны перебрать все записи в строке, соответствующей v в матрице смежности, чтобы найти все ненулевые записи, что требует n = | V | сканирование в целом. Поэтому общая работа, требуемая для DFS, равна O (| V | 2) = O (n 2) в этом случае.