Коли практично використовувати глибинний пошук (DFS) проти пошуку по ширині (BFS)? [зачинено]


345

Я розумію відмінності між DFS та BFS, але мені цікаво знати, коли практичніше використовувати один над іншим?

Чи може хтось навести приклади того, як DFS козирував BFS і навпаки?


4
Можливо, ви можете згадати повні терміни для DFS та BFS до питання - люди можуть не знати цих абревіатур.
Ганс-Пітер Штерр




Примітка згадує деякі сценарії застосування BFS та DFS
Yossarian42

Відповіді:


353

Це значною мірою залежить від структури дерева пошуку та кількості та місця розташування рішень (він же шукає елементи).

  • Якщо ви знаєте, що рішення знаходиться недалеко від кореня дерева, перший пошук по ширині (BFS) може бути кращим.
  • Якщо дерево дуже глибоке і рішення рідкісні, то перший пошук глибини (DFS) може зайняти надзвичайно багато часу, але BFS може бути швидшим.

  • Якщо дерево дуже широке, BFS може потребувати занадто багато пам'яті, тому це може бути абсолютно непрактично.

  • Якщо розчини часті, але розташовані глибоко в дереві, BFS може бути недоцільним.

  • Якщо дерево пошуку дуже глибоке, у будь-якому випадку вам доведеться обмежити глибину пошуку для глибини першого пошуку (DFS) (наприклад, з ітераційним поглибленням).

Але це лише великі правила; вам, мабуть, доведеться експериментувати.


4
Рекурсія AFAIK, як правило, потребує більше пам'яті, ніж ітерація.
Марек Марчак

3
@MarekMarczak Я не зовсім бачу, що ти хочеш сказати. Якщо ви приймаєте BFS як ітерацію - якщо простір рішення не легко перерахувати, можливо, вам доведеться зберігати весь n-й рівень дерева пошуку в пам'яті, щоб перерахувати n + 1-й рівень.
Ганс-Пітер Штерр

11
@MarekMarczak Ітеративна версія DFS використовує стек. Рекурсія проти Ітерації - це зовсім окрема тема.
Клінт Дейго

Ще один випадок, який прийшов до тями: BFS корисний (необхідний) у випадку, коли графік "нескінченний". Як скажімо, шахова дошка, яка тягнеться до нескінченності у всіх напрямках. DFS ніколи не повернеться. BFS гарантовано знайде те, що шукає, якщо ця умова задовольняється.
ThePartyTurtle

157

Поглиблений пошук

Швидкісні пошуки часто використовуються при моделюванні ігор (і ігрових ситуаціях у реальному світі). У типовій грі ви можете вибрати одну з кількох можливих дій. Кожен вибір призводить до подальших виборів, кожен з яких призводить до подальших виборів тощо у графік можливостей дерева, що постійно розширюється.

введіть тут опис зображення

Наприклад, у таких іграх, як «Шахи», тик-так-носок, коли ви вирішуєте, який хід зробити, ви можете подумки уявити собі рух, то можливі відповіді опонента, потім ваші відповіді тощо. Ви можете вирішити, що робити, побачивши, який хід призводить до найкращого результату.

Лише деякі шляхи в ігровому дереві ведуть до вашої виграші. Деякі призводять до виграшу опонента, коли ви досягнете такого кінця, ви повинні створити резервну копію або відхилитись до попереднього вузла і спробувати інший шлях. Таким чином ви досліджуєте дерево, поки не знайдете шлях з успішним висновком. Тоді ви робите перший рух по цьому шляху.


Перший пошук

Перший широтний пошук має цікаву властивість: він спочатку знаходить усі вершини, які знаходяться в одному краю від початкової точки, потім всі вершини, які знаходяться на двох ребрах, і так далі. Це корисно, якщо ви намагаєтесь знайти найкоротший шлях від початкової вершини до заданої вершини. Ви запускаєте BFS, і коли ви знайдете вказану вершину, ви знаєте, що шлях, який ви простежили до цього часу, - це найкоротший шлях до вузла. Якби був коротший шлях, BFS знайшов би його вже.

Пошук за шириною може використовуватися для пошуку сусідніх вузлів в однорангових мережах, таких як BitTorrent, GPS-системи для пошуку сусідніх локацій, сайтів соціальних мереж, щоб знайти людей на вказаній відстані та подібні речі.


113

Приємне пояснення з http://www.programmerinterview.com/index.php/data-structures/dfs-vs-bfs/

Приклад BFS

Ось приклад того, як виглядатиме BFS. Це щось на кшталт обходу дерева порядку рівня, де ми будемо використовувати QUEUE з ІТЕРАТИВНИМ підходом (здебільшого РЕКУРСІЯ закінчується DFS). Цифри представляють порядок доступу до вузлів у BFS:

введіть тут опис зображення

Перший пошук на глибині ви починаєте з кореня та слідуєте за якоюсь можливою гілкою дерева до тих пір, поки не знайдеться той вузол, який ви шукаєте, або не потрапите на листовий вузол (вузол без дітей). Якщо ви потрапили на вузол листя, то продовжуйте пошук найближчого предка з недослідженими дітьми.

Приклад ДФС

Ось приклад того, як виглядатиме DFS. Я думаю, що обхід після замовлення у двійковому дереві спочатку почне працювати з рівня Leaf. Цифри представляють порядок доступу до вузлів у DFS:

введіть тут опис зображення

Відмінності між DFS та BFS

Порівнюючи BFS та DFS, велика перевага DFS полягає в тому, що він має значно менші вимоги до пам'яті, ніж BFS, тому що не потрібно зберігати всі дочірні вказівники на кожному рівні. Залежно від даних і того, що ви шукаєте, DFS або BFS можуть бути вигідними.

Наприклад, зважаючи на генеалогічне дерево, якщо хтось шукав когось на дереві, хто ще живий, то можна було б припустити, що людина опиниться на дні дерева. Це означає, що BFS знадобиться дуже багато часу, щоб досягти цього останнього рівня. Однак DFS знайде мету швидше. Але, якби хтось шукав члена родини, який помер дуже давно, то ця людина була б ближче до верхівки дерева. Тоді BFS, як правило, буде швидшим, ніж DFS. Отже, переваги або варіюються залежно від даних та того, що ви шукаєте.

Ще один приклад - Facebook; Пропозиція про друзів друзів. Нам потрібні негайні друзі для пропозиції, де ми можемо використовувати BFS. Можемо знайти найкоротший шлях або виявити цикл (за допомогою рекурсії), який ми можемо використовувати DFS.


Що таке "обхід після замовлення у двійковому дереві"?
Кайл Делані

8
Чи вважає DFS найкоротший шлях кращим за BFS? Я думаю, що це навпаки. Я думаю, що BFS знаходить найкоротший шлях. Чи не так?
Naveen Gabriel

1
Був би вдячний більше, якби ви дали кредити джерелу. Частину порівняння підібрано з "Структури даних, спрощеної на Яві" Нарасими Каруманчі.
learnntogrow-зростанняtolearn

Звичайно, я можу це оновити, але не чекаючи, що хтось тут вдячний. Просто хочу допомогти бідним тех, як я.
Канагавелу Сугумар

1
@KyleDelaney є три замовлення, в яких можна перемістити дерево - попереднє замовлення, замовлення та порядок замовлення. Вони відповідають відповідно до інфіксів префікса та позначення постфіксу. Коли ви переходите по дереву вниз, а потім створюєте резервну копію, якщо ви вибираєте вузол, коли ви відвідуєте його вперше, це попереднє замовлення, якщо вдруге воно не впорядковане, якщо в останній раз це відбувається після замовлення. Ви можете фактично серіалізувати дерево таким чином, і поки ви пам’ятаєте порядок, який ви використовували, ви можете відновити дерево після серіалізації.
Дейв

43

Перший пошук ширини - це найкращий підхід, коли глибина дерева може змінюватися, і вам потрібно лише шукати частину дерева для пошуку рішення. Наприклад, пошук найкоротшого шляху від початкового значення до кінцевого значення - хороше місце для використання BFS.

Перший пошук по глибині зазвичай використовується, коли потрібно шукати все дерево. Це легше реалізувати (використовуючи рекурсію), ніж BFS, і вимагає меншого стану: Хоча BFS вимагає зберігати весь 'кордон', DFS вимагає лише ви зберігати список батьківських вузлів поточного елемента.


26

DFS є більш економічним для простору, ніж BFS, але може зайняти зайві глибини.

Їх назви показові: якщо є велика ширина (тобто великий коефіцієнт розгалуження), але дуже обмежена глибина (наприклад, обмежена кількість "ходів"), то DFS може бути більш переважним перед BFS.


На IDDFS

Слід зазначити, що існує маловідомий варіант, який поєднує в собі космічну ефективність DFS, але (кумулятивно) відвідування BFS за рівнем порядку - це ітеративний поглиблений пошук в глибині перших . Цей алгоритм переглядає деякі вузли, але він лише вносить постійний коефіцієнт асимптотичної різниці.


1
Це не обов'язково більш просторово використовувати. Розгляньте, наприклад, графік шляху.
RB

16

Коли ви підходите до цього питання як програміст, виділяється один фактор: якщо ви використовуєте рекурсію, то пошук на глибині першого простіший здійснити, тому що вам не потрібно підтримувати додаткову структуру даних, що містить вузли, які ще слід вивчити.

Ось перший поглиблений пошук неорієнтованого графіка, якщо ви зберігаєте "вже відвідану" інформацію у вузлах:

def dfs(origin):                               # DFS from origin:
    origin.visited = True                      # Mark the origin as visited
    for neighbor in origin.neighbors:          # Loop over the neighbors
        if not neighbor.visited: dfs(next)     # Visit each neighbor if not already visited

Якщо зберігати "вже відвідану" інформацію в окремій структурі даних:

def dfs(node, visited):                        # DFS from origin, with already-visited set:
    visited.add(node)                          # Mark the origin as visited
    for neighbor in node.neighbors:            # Loop over the neighbors
        if not neighbor in visited:            # If the neighbor hasn't been visited yet,
            dfs(node, visited)                 # then visit the neighbor
dfs(origin, set())

Порівнюйте це з першим широким пошуком, де вам потрібно підтримувати окрему структуру даних для списку вузлів, які ще слід відвідати, незалежно від того.



5

Для BFS ми можемо розглянути приклад Facebook. Ми отримуємо пропозицію додати друзів із профілю FB з інших профілів друзів. Припустимо, A-> B, тоді як B-> E і B-> F, тому A отримає пропозицію для E і F. Вони повинні використовувати BFS для читання до другого рівня. DFS більше базується на сценаріях, де ми хочемо прогнозувати щось на основі даних, які ми маємо від джерела до місця призначення. Як уже говорилося про шахи чи судоку. Коли я щось інше тут, я вважаю, що DFS слід використовувати для найкоротшого шляху, оскільки DFS спочатку покриє весь шлях, тоді ми можемо визначити найкращий. Але оскільки BFS буде використовувати жадібний підхід, так, можливо, це виглядає як найкоротший шлях, але кінцевий результат може відрізнятися. Дайте мені знати, чи моє розуміння неправильне.


Зараз мій коментар трохи пізно. Але щоб знайти найкоротший шлях, слід використовувати BFS. Однак "DFS базується більше на сценаріях, коли ми хочемо прогнозувати щось на основі даних, які ми маємо від джерела до місця призначення" - це геніальна річ, яку ви сказали! Кудо !!
Оскарзіто

4

Деякі алгоритми залежать від конкретних властивостей DFS (або BFS) для роботи. Наприклад, алгоритм Hopcroft і Tarjan для пошуку 2-з'єднаних компонентів використовує той факт, що кожен вже відвіданий вузол, з яким стикається DFS, перебуває на шляху від кореня до досліджуваного на даний момент вузла.


4

Далі йде вичерпна відповідь на запитання.

Простими словами:

Алгоритм першого пошуку ширини (BFS) від назви "Ширина" виявляє всіх сусідів вузла через виворітні краї вузла, потім він виявляє невідомих сусідів згаданих раніше сусідів через їхні краї і так далі, поки все відвідуються вузли, доступні від оригінального джерела (ми можемо продовжувати та брати інше оригінальне джерело, якщо залишилися непроглянуті вузли тощо). Ось чому з його допомогою можна знайти найкоротший шлях (якщо такий є) від вузла (оригінального джерела) до іншого вузла, якщо вага країв рівномірний.

Алгоритм "Перший глибинний пошук" (DFS) від своєї назви "Глибина" виявляє невідомих сусідів останнього виявленого вузла x через його край. Якщо від вузла x немає невідомого сусіда, алгоритм здійснює відстеження для виявлення невідомих сусідів вузла (через його вихідні краї), з якого було виявлено вузол x тощо, до тих пір, поки не будуть відвідані всі вузли, доступні від початкового джерела (ми можемо продовжувати та брати інше оригінальне джерело, якщо залишилися непроглянуті вузли тощо).

І BFS, і DFS можуть бути неповними. Наприклад, якщо коефіцієнт розгалуження вузла нескінченний або дуже великий для підтримки ресурсів (пам'яті) (наприклад, при зберіганні вузлів, які будуть виявлені далі), BFS не є повним, навіть якщо шуканий ключ може знаходитись на відстані з кількох країв від початкового джерела. Цей нескінченний розгалужуючий фактор може бути зумовлений нескінченним вибором (сусідні вузли) з даного вузла для виявлення. Якщо глибина нескінченна або дуже велика, щоб ресурси (пам'ять) підтримували (наприклад, при зберіганні вузлів, які будуть виявлені далі), то DFS не є повним, навіть якщо шуканий ключ може бути третім сусідом початкового джерела. Ця нескінченна глибина може бути через ситуацію, коли для кожного вузла алгоритм виявляє, принаймні, новий вибір (сусідній вузол), який раніше не відвідували.

Тому ми можемо зробити висновок, коли використовувати BFS та DFS. Припустимо, ми маємо справу з керованим обмеженим фактором розгалуження та керованою обмеженою глибиною. Якщо шуканий вузол неглибокий, тобто доступний після деяких ребер від початкового джерела, тоді краще використовувати BFS. З іншого боку, якщо шуканий вузол є глибоким, тобто доступним після великої кількості ребер від початкового джерела, тоді краще використовувати DFS.

Наприклад, у соціальній мережі, якщо ми хочемо шукати людей, які мають подібні інтереси конкретної людини, ми можемо застосувати BFS від цієї людини як джерельне джерело, тому що в основному ці люди будуть його прямими друзями або друзями друзів, тобто одним або два ребра далеко. З іншого боку, якщо ми хочемо шукати людей, які мають абсолютно різні інтереси конкретної людини, ми можемо застосувати DFS від цієї людини як джерельне джерело, тому що в основному ці люди будуть дуже далекі від нього, тобто товариш друга друга .... тобто занадто багато ребер далеко.

Застосування BFS та DFS можуть відрізнятися також через механізм пошуку в кожному з них. Наприклад, ми можемо використовувати або BFS (припускаючи, що коефіцієнт розгалуження є керованим), або DFS (припускаючи, що глибина керована), коли ми просто хочемо перевірити доступність від одного вузла до іншого, не маючи інформації, де цей вузол може бути. Також обидва вони можуть вирішувати такі самі завдання, як топологічне сортування графіка (якщо він є). BFS можна використовувати для пошуку найкоротшого шляху з одиничними ваговими краями від вузла (оригінального джерела) до іншого. В той час, як DFS може використовуватися для вичерпання всіх варіантів через його характер заглиблення, як виявлення найдовшого шляху між двома вузлами в ациклічному графіку. Також DFS можна використовувати для виявлення циклу в графіку.

Зрештою, якщо ми маємо нескінченну глибину і нескінченний розгалужуючий фактор, ми можемо використовувати Ітеративний поглиблений пошук (IDS).


2

За властивостями DFS та BFS. Наприклад, коли ми хочемо знайти найкоротший шлях. ми зазвичай використовуємо bfs, це може гарантувати "найкоротший". але лише dfs може гарантувати, що ми можемо прийти з цієї точки, можемо досягти цієї точки, не може гарантувати "найкоротшого".


2

Я думаю, це залежить від того, з якими проблемами ви стикаєтесь.

  1. найкоротший шлях на простому графіку -> bfs
  2. всі можливі результати -> dfs
  3. пошук по графіку (трактуйте дерево, martix також як графік) -> dfs ....

Якщо до списку додати порожній рядок, відповідь буде виглядати набагато краще.
montonero

1

Оскільки пошуки заглиблень-перших використовують стек під час обробки вузлів, зворотний трекінг надається за допомогою DFS. Оскільки Breadth-First Searches використовує чергу, а не стек, щоб відслідковувати, які вузли обробляються, зворотний трекінг не надається з BFS.


1

Коли ширина дерева дуже велика, а глибина невелика, використовуйте DFS, оскільки стек рекурсії не буде переповнений. Використовуйте BFS, коли ширина невелика, а глибина дуже велика для обходу дерева.


0

Це хороший приклад для того, щоб продемонструвати, що BFS є кращим, ніж DFS в певному випадку. https://leetcode.com/problems/01-matrix/

При правильній реалізації обидва рішення повинні відвідувати комірки, що мають більшу відстань, ніж поточна комірка +1. Але DFS є неефективним і неодноразово відвідував одну і ту ж клітинку, що призводить до складності O (n * n).

Наприклад,

1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
0,0,0,0,0,0,0,0,

0

Це залежить від ситуації, в якій він використовується. Щоразу, коли у нас виникає проблема проходження графа, ми робимо це з певною метою. Коли виникає проблема знайти найкоротший шлях у невагомому графіку або знайти, чи графік двосторонній, ми можемо використовувати BFS. Для проблем виявлення циклу або будь-якої логіки, що вимагає зворотного відстеження, ми можемо використовувати DFS.

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