Ширина первой Vs Глубина

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

Ответ 1

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

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

    A
   / \
  B   C
 /   / \
D   E   F

A глубина первый обход посетит узлы в этом порядке

A, B, D, C, E, F

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

A ширина первый обход посетил бы node в этом порядке

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

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


В этот момент я все еще немного обманывал. С небольшим умом вы можете также работать с узлами в следующем порядке:

D, B, E, F, C, A

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

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

Ответ 2

Понимание условий:

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

Understanding Breadth and Depth


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

Depth-First Search

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

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

  • Соблюдайте следующие правила: толкните первую вершину A в Stack

    1. Если возможно, посетите соседнюю не посещенную вершину, отметьте ее как посещенную и поместите в стек.
    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;
    }
    
  • Приложения: Поиск в глубину часто используется при моделировании игр (и игровых ситуаций в реальном мире). В типичной игре вы можете выбрать одно из нескольких возможных действий. Каждый выбор ведет к дальнейшему выбору, каждый из которых ведет к дальнейшему выбору, и так далее, в постоянно расширяющийся древовидный график возможностей.


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

Breadth-First Search

  • Алгоритм поиска в ширину любит оставаться как можно ближе к начальной точке.
  • Этот вид поиска обычно реализуется с использованием Queue.
  • Соблюдайте правила: сделайте начальную вершину A текущей вершиной
    1. Посетите следующую не посещенную вершину (если она есть), которая находится рядом с текущей вершиной, отметьте ее и вставьте в очередь.
    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;
    }
    
  • Приложения: Поиск в ширину сначала находит все вершины, которые находятся на расстоянии одного ребра от начальной точки, затем все вершины, которые находятся на расстоянии двух ребер, и так далее. Это полезно, если вы пытаетесь найти кратчайший путь от начальной вершины до данной вершины.

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

Ответ 3

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

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

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

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

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

Ответ 4

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

enter image description here

Ширина первого обхода:
Пройдите через каждый уровень слева направо.

"Я 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 a tree)  
Grab the Root of the Left. (D)  
Then Check the Left of D. (It a tree)  
Grab the Root of the Left (B)  
Then Check the Left of B. (A)  
Check the Right of B. (C, and it a leaf node. Finish B tree. Continue D tree)  
Check the Right of D. (It 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 a tree)  
Grab the Root of I Tree. (I)  
Check the Left. (H, it a leaf.)  
Check the Right. (K, it 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 a D Tree)  
Check the Left of the D Tree. (It 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 a E Tree)  
Check the Left of the E Tree. (Nothing)  
Check the Right of the E Tree. (F, it 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 методов глубинного обхода и того, как они обычно используются:
"In-Order Traversal будет печатать значения [для BST (дерево двоичного поиска)]"
"Обход предварительного заказа используется для создания копии [дерева двоичного поиска]".
Msgstr "Обратный путь по порядку используется для удаления [бинарного дерева поиска]."
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing