BFS обычно описывается примерно так (из Википедии ).
1 procedure BFS(G,start_v):
2 let Q be a queue
3 label start_v as discovered
4 Q.enqueue(start_v)
5 while Q is not empty
6 v = Q.dequeue()
7 if v is the goal:
8 return v
9 for all edges from v to w in G.adjacentEdges(v) do
10 if w is not labeled as discovered:
11 label w as discovered
12 w.parent = v
13 Q.enqueue(w)
Проблема несколько тонкая: она прячется в строке 3! Вопрос в том, какую структуру данных мы будем использовать для хранения обнаруженных вершин.
Самое простое решение - использовать логический массив с одной записью на вершину. В этом случае мы должны инициализировать каждый элемент массива, false
и это занимает время Θ(|V|) . Это применимо для каждого графа, даже если ребер нет вообще, поэтому мы не можем предполагать какую-либо связь между |V|и |E|и мы получаем время работы O(|V|+|E|) .
Можем ли мы избежать структуры данных со временем инициализации Θ(|V|) ? Нашей первой попыткой может быть использование связанного списка. Однако теперь проверка того, была ли обнаружена вершина (строка 10), занимает линейное время по числу посещенных вершин, а не постоянное время, как раньше. Это означает, что время выполнения становится O(|V||E|) , что намного хуже в худшем случае. (Обратите внимание, что мы не хотим переписывать это какO(|E|2) так как это еще хуже: это может быть так же плохо, как|V|4 , тогда как|V||E|≤|V|3
O(log|V|)O(|E|log|V|)
c|E|+1c+2c+4c+⋯+2|E|≤4|E|, Поиски и вставки в хеш-таблицу амортизируются O(1) поэтому мы действительно получаем время выполнения O(|E|) .
O(|E|)4|E|O(|E|)O(|V|+|E|)