Сначала в ширину против сначала в глубину

При перемещении по дереву / графику какая разница между сначала в ширину и сначала в глубину? Любые примеры кодирования или псевдокода были бы хороши.


person Ted Smith    schedule 26.03.2009    source источник
comment
Вы проверяли википедию (сначала глубина, сначала в ширину)? На этих страницах есть примеры кода и множество красивых картинок.   -  person rmeador    schedule 27.03.2009
comment
У меня тоже была эта мысль, но приведенные примеры немного лучше, чем те, что можно найти в Википедии ...   -  person jonnybazookatone    schedule 21.07.2016
comment
См. Этот визуальный пример. Хотя я хотел бы опубликовать это как ответ, поскольку это только ссылка, она снизит голоса, следовательно, комментарий.   -  person Guy Coder    schedule 24.08.2020


Ответы (4)


Эти два термина различают два разных способа ходьбы по дереву.

Наверное, проще всего показать разницу. Рассмотрим дерево:

    A
   / \
  B   C
 /   / \
D   E   F

При первом обходе глубины узлы будут посещаться в этом порядке.

A, B, D, C, E, F

Обратите внимание, что вы полностью опускаетесь на одну ногу, прежде чем двигаться дальше.

При первом обходе ширины узел будет посещаться в этом порядке.

A, B, C, D, E, F

Здесь мы проходим полностью через каждый уровень, прежде чем спускаться вниз.

(Обратите внимание, что есть некоторая двусмысленность в порядках обхода, и я обманул, чтобы поддерживать порядок "чтения" на каждом уровне дерева. В любом случае я мог бы добраться до B до или после C, и аналогичным образом я мог бы добраться до E до или после F. Это может иметь значение, а может и не иметь значения, зависит от вашего приложения ...)


Оба вида обхода могут быть выполнены с помощью псевдокода:

Store the root node in Container
While (there are nodes in Container)
   N = Get the "next" node from Container
   Store all the children of N in Container
   Do some work on N

Разница между двумя порядками обхода заключается в выборе Container.

  • Для параметра сначала глубина используйте стопку. (Рекурсивная реализация использует стек вызовов ...)
  • Для в ширину используйте очередь.

Рекурсивная реализация выглядит как

ProcessNode(Node)
   Work on the payload Node
   Foreach child of Node
      ProcessNode(child)
   /* Alternate time to work on the payload Node (see below) */

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


На данный момент я еще немного схитрил. Проявив немного смекалки, вы также можете поработать над узлами в следующем порядке:

D, B, E, F, C, A

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

Этот обход довольно естественен в рекурсивной реализации (используйте строку «Альтернативное время» выше вместо первой строки «Работа») и не слишком, если вы используете явный стек, но я оставь это как упражнение.

person dmckee --- ex-moderator kitten    schedule 26.03.2009
comment
@dmckee Спасибо! Я полагаю, вы имели в виду Работу над полезной нагрузкой в ​​Node, верно? - person batbrat; 13.02.2012
comment
Возможно, стоит отметить, что вы можете изменить версию, ориентированную на глубину, чтобы получить префикс (A, B, D, C, E, F - первый из представленных), инфиксный (D, B, A, E, C, F - используется для сортировки: добавить как дерево AVL, затем прочитать инфикс) или постфикс (D, B, E, F, C, A представленная альтернатива) обход. Имена даны по позиции, в которой вы обрабатываете корень. Следует отметить, что инфикс действительно имеет смысл только для двоичных деревьев. @batbrat, это имена ... учитывая время, прошедшее с того момента, как вы спросили, вы, вероятно, уже знаете. - person Theraot; 01.11.2015
comment
@Theraot, спасибо, что добавили это! Да, я знаю об этих видах обходов и почему Infix имеет смысл только для двоичных деревьев. - person batbrat; 18.11.2015
comment
Как решить, какое решение имеет лучшую пространственную или временную сложность? - person IgorGanapolsky; 10.03.2016
comment
@IgorGanapolsky Принципиально должно быть одинаковым для обоих (в конце концов, они используют один и тот же код). Более интересным вопросом будет то, как они влияют на кеш и рабочий набор, но я думаю, что это будет зависеть от морфологии дерева. - person dmckee --- ex-moderator kitten; 10.03.2016

Понимание терминов:

Это изображение должно дать вам представление о контексте, в котором используются слова ширина и глубина.

Понимание широты и глубины


Поиск в глубину:

Поиск в глубину

  • Алгоритм поиска в глубину действует так, как если бы он хотел как можно быстрее уйти как можно дальше от начальной точки.

  • Обычно он использует Stack, чтобы запомнить, куда он должен идти, когда заходит в тупик.

  • Правила, которым нужно следовать: надавите на первую вершину A на Stack

    1. If possible, visit an adjacent unvisited vertex, mark it as visited, and push it on the stack.
    2. Если вы не можете следовать Правилу 1, по возможности извлеките вершину из стека.
    3. Если вы не можете следовать Правилу 1 или Правилу 2, все готово.
  • Код Java:

    public void searchDepthFirst() {
        // Begin at vertex 0 (A)
        vertexList[0].wasVisited = true;
        displayVertex(0);
        stack.push(0);
        while (!stack.isEmpty()) {
            int adjacentVertex = getAdjacentUnvisitedVertex(stack.peek());
            // If no such vertex
            if (adjacentVertex == -1) {
                stack.pop();
            } else {
                vertexList[adjacentVertex].wasVisited = true;
                // Do something
                stack.push(adjacentVertex);
            }
        }
        // Stack is empty, so we're done, reset flags
        for (int j = 0; j < nVerts; j++)
            vertexList[j].wasVisited = false;
    }
    
  • Приложения: поиск в глубину часто используется при моделировании игр (и игровых ситуаций в реальном мире). В обычной игре вы можете выбрать одно из нескольких возможных действий. Каждый выбор ведет к дальнейшему выбору, каждый из которого ведет к дальнейшему выбору, и так далее до постоянно расширяющегося древовидного графа возможностей.


Поиск в ширину:

Поиск в ширину

  • Алгоритм поиска в ширину предпочитает оставаться как можно ближе к начальной точке.
  • Такой поиск обычно реализуется с использованием Queue.
  • Rules to follow: Make starting Vertex A the current vertex
    1. Visit the next unvisited vertex (if there is one) that’s adjacent to the current vertex, mark it, and insert it into the queue.
    2. Если вы не можете выполнить Правило 1, потому что больше нет непосещенных вершин, удалите вершину из очереди (если возможно) и сделайте ее текущей вершиной.
    3. Если вы не можете выполнить Правило 2, потому что очередь пуста, все готово.
  • Код Java:

    public void searchBreadthFirst() {
        vertexList[0].wasVisited = true;
        displayVertex(0);
        queue.insert(0);
        int v2;
        while (!queue.isEmpty()) {
            int v1 = queue.remove();
            // Until it has no unvisited neighbors, get one
            while ((v2 = getAdjUnvisitedVertex(v1)) != -1) {
                vertexList[v2].wasVisited = true;
                // Do something
                queue.insert(v2);
            }
        }
        // Queue is empty, so we're done, reset flags
        for (int j = 0; j < nVerts; j++) 
            vertexList[j].wasVisited = false;
    }
    
  • Приложения: поиск в ширину сначала находит все вершины, которые находятся на расстоянии одного ребра от начальной точки, а затем все вершины, которые находятся на расстоянии двух краев и т. д. Это полезно, если вы пытаетесь найти кратчайший путь от начальной вершины до данной вершины.

Надеюсь, этого должно быть достаточно для понимания поисковых запросов в ширину и в глубину. Для дальнейшего чтения я бы порекомендовал главу «Графики» из прекрасной книги Роберта Лафора о структурах данных.

person Yogesh Umesh Vaity    schedule 06.05.2016
comment
Если бы у меня было еще десять голосов, я бы так и сделал. - person snr; 21.05.2017
comment
@snr ты мог бы наградить наградой;) - person Snow; 27.03.2019
comment
@Snow, если вы расскажете о его директивах, я могу. Я не знаю, как это сделать. - person snr; 27.03.2019
comment
Спасибо @snr, я так рад получить свою первую награду. Я очень ценю. - person Yogesh Umesh Vaity; 28.03.2019
comment
Спасибо @Snow, я рад, что вы, ребята, нашли мой ответ полезным. - person Yogesh Umesh Vaity; 28.03.2019
comment
@YogeshUmeshVaity Отличный ответ - это классический пример хорошо объясненного ответа StackOverflow / StackExchange высшего уровня. id = dmid: // uu745gurulevel1622917502 - person dreftymac; 05.06.2021

Учитывая это двоичное дерево:

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

Обход в ширину:
Пересекайте каждый уровень слева направо.

"Я G, мои дети D и я, мои внуки B, E, H и K, их внуки A, C, F"

- Level 1: G 
- Level 2: D, I 
- Level 3: B, E, H, K 
- Level 4: A, C, F

Order Searched: G, D, I, B, E, H, K, A, C, F

Обход по глубине:
Обход не выполняется ПОСЕЧНО целыми уровнями за раз. Вместо этого обход сначала погружается в ГЛУБИНУ (от корня к листу) дерева. Однако это немного сложнее, чем просто вверх и вниз.

Есть три метода:

1) PREORDER: ROOT, LEFT, RIGHT.
You need to think of this as a recursive process:  
Grab the Root. (G)  
Then Check the Left. (It's a tree)  
Grab the Root of the Left. (D)  
Then Check the Left of D. (It's a tree)  
Grab the Root of the Left (B)  
Then Check the Left of B. (A)  
Check the Right of B. (C, and it's a leaf node. Finish B tree. Continue D tree)  
Check the Right of D. (It's a tree)  
Grab the Root. (E)  
Check the Left of E. (Nothing)  
Check the Right of E. (F, Finish D Tree. Move back to G Tree)  
Check the Right of G. (It's a tree)  
Grab the Root of I Tree. (I)  
Check the Left. (H, it's a leaf.)  
Check the Right. (K, it's a leaf. Finish G tree)  
DONE: G, D, B, A, C, E, F, I, H, K  

2) INORDER: LEFT, ROOT, RIGHT
Where the root is "in" or between the left and right child node.  
Check the Left of the G Tree. (It's a D Tree)  
Check the Left of the D Tree. (It's a B Tree)  
Check the Left of the B Tree. (A)  
Check the Root of the B Tree (B)  
Check the Right of the B Tree (C, finished B Tree!)  
Check the Right of the D Tree (It's a E Tree)  
Check the Left of the E Tree. (Nothing)  
Check the Right of the E Tree. (F, it's a leaf. Finish E Tree. Finish D Tree)...  
Onwards until...   
DONE: A, B, C, D, E, F, G, H, I, K  

3) POSTORDER: 
LEFT, RIGHT, ROOT  
DONE: A, C, B, F, E, D, H, K, I, G

Использование (также известное как нас волнует):
Мне очень понравилось это простое объяснение Quora методов обхода глубины и того, как они обычно используются:
«Обход по порядку будет напечатан значения [для BST (двоичного дерева поиска)] "
" Предварительный обход используется для создания копии [двоичного дерева поиска]. "
" Последующий обход используется для удаления [двоичного дерево поиска]. "
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing

person msyinmei    schedule 02.03.2018

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

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

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

Я пока не видел какой-либо интуитивной интерпретации DFS (только стандартная для лабиринта, но она не такая мощная, как BFS и наводнение), поэтому мне кажется, что BFS, кажется, лучше коррелирует с физическими явлениями, как описано выше, в то время как DFS лучше коррелирует с дилеммой выбора рациональных систем (т. Е. Люди или компьютеры решают, какой ход сделать в шахматной партии или выйти из лабиринта).

Итак, для меня разница между тем, какое природное явление лучше всего соответствует их модели распространения (пересечения) в реальной жизни.

person user5193682    schedule 02.08.2016
comment
Вы можете реализовать их с помощью аналогичного алгоритма, просто используйте стек для DFS и очередь для BFS. Проблема с BFS в том, что вам нужно отслеживать все узлы, которые вы видели до сих пор. DFS в физике .. Я представляю себе альтернативные вселенные, и вы хотите одну с жизнью, все дети корня, разные большие взрывы, и вы идете вниз до смерти вселенной, без жизни? вы возвращаетесь к последней бифуркации и пробуете еще один поворот, пока все не будут исчерпаны, и вы перейдете к следующему большому взрыву, устанавливающему новые физические законы для новой вселенной. супер интуитивно понятный. Хорошая проблема - найти дорогу с лошадью на шахматной доске. - person juanmf; 13.08.2017