Чому кажуть, що пошук за шириною починається в часі ?


9

Часто зазначається (наприклад, у Вікіпедії ), що час роботи першого пошуку в широті (BFS) на графіку є . Однак будь-який підключений графік має і навіть у непідключеному графіку BFS ніколи не буде дивитися на вершину за межами компонента, який містить стартову вершину. Цей компонент містить не більше країв, тому він містить щонайбільше вершин, і це єдині, які алгоритм відвідає.G=(V,E)O(|V|+|E|)|V||E|+1|E||E|+1

Це означає, що , то чому б нам не сказати, що час роботи - це просто ?|V|+|E|2|E|+1O(|E|)

Це з'явилося в коментарях до питання про час роботи алгоритму Disjkstra .


Чому ви вважаєте, що існує початкова вершина? Наприклад, BFS у задачі про максимальну відповідність починається з усіх неперевершених вершин алгоритму карпа Hopcroft. У цьому випадку, якщо даний графік є лісом з багатьох пов'язаних компонентів, у нас буде більше вершин, ніж обріз, і ми відвідаємо їх усі
narek Bojikian

2
@narekBojikian Хоча BFS можна використовувати різними способами, якщо він представлений як окремий алгоритм, він, як правило, завжди має початкову вершину.
Девід Річербі

Відповіді:


9

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|)

Чи можемо ми уникнути наявності структури даних із часом ініціалізації ? Нашою першою спробою може бути використання пов'язаного списку. Однак зараз тестування, чи була виявлена ​​вершина (рядок 10), займає лінійний час у кількості відвідуваних вершин, а не постійний час, як раніше. Це означає, що час роботи стає , що в гіршому випадку набагато гірше. (Зверніть увагу, що ми не хочемо переписувати це як оскільки це ще гірше: це може бути так само погано, як , тоді як )Θ(|V|)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|) час роботи, тому не варто використовувати хеш-таблицю, щоб видалити домінуючий термін, враховуючи практичну вартість цього.


1
Я думаю, що це може бути занадто сильним, щоб стверджувати, що хеш-таблиці на практиці мають низьку ефективність кешу. Якщо це здійснено за допомогою ланцюжка (тобто зв'язаних списків), я згоден. Але якщо це реалізовано з безперервним шматочком пам’яті та відкритою адресацією, не так вже й багато.
Juho

Чудова відповідь справді! Хоча одна гранична нота, хеш-таблиці з динамічним розміром дійсно є хорошим вибором не тільки якщо є багато невеликих компонентів, але й якщо значення хеша для будь-якої вершини обмежено розумною константою, і це трапляється часто. Приємна відповідь!
Карлос Лінарес Лопес

1
Девіде, у мене були подібні думки років тому. Я думаю, що відповідь полягає в історичній перспективі.
kelalaka
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.