Podczas przechodzenia przez drzewo / wykres, jaka jest różnica między Najpierw szerokość i najpierw głębokość? Wszelkie przykłady kodowania lub pseudokodu byłyby świetne.
Podczas przechodzenia przez drzewo / wykres, jaka jest różnica między Najpierw szerokość i najpierw głębokość? Wszelkie przykłady kodowania lub pseudokodu byłyby świetne.
Odpowiedzi:
Te dwa terminy rozróżniają dwa różne sposoby chodzenia po drzewie.
Najłatwiej jest chyba pokazać różnicę. Rozważ drzewo:
A
/ \
B C
/ / \
D E F
Głębokość pierwszy przejścia odwiedzi węzły w tej kolejności
A, B, D, C, E, F
Zwróć uwagę, że przed przejściem dalej schodzisz całą nogę w dół .
Szerokość pierwszy przejścia odwiedzi węzeł w tej kolejności
A, B, C, D, E, F
Tutaj pracujemy całą drogę całej każdym poziomie przed zejściem w dół.
(Zauważ, że jest pewna dwuznaczność w kolejności przechodzenia i oszukiwałem, aby utrzymać kolejność „czytania” na każdym poziomie drzewa. W każdym przypadku mogłem dostać się do B przed lub po C, i podobnie mogłem dostać się do E przed lub po F. To może mieć znaczenie lub nie, zależy od twojego zastosowania ...)
Za pomocą pseudokodu można uzyskać oba rodzaje przechodzenia:
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
Różnica między dwoma porządkami przejścia polega na wyborze Container
.
Jak wygląda rekurencyjna implementacja
ProcessNode(Node)
Work on the payload Node
Foreach child of Node
ProcessNode(child)
/* Alternate time to work on the payload Node (see below) */
Rekurencja kończy się, gdy dojdziesz do węzła, który nie ma dzieci, więc jest gwarantowana dla skończonych, acyklicznych grafów.
W tym momencie nadal trochę oszukiwałem. Przy odrobinie sprytu możesz również pracować nad węzłami w następującej kolejności:
D, B, E, F, C, A
co jest odmianą pierwszej głębi, w której nie wykonuję pracy w każdym węźle, dopóki nie wrócę na drzewo. Jednak odwiedziłem wyższe węzły w drodze w dół, aby znaleźć ich dzieci.
To jest dość naturalne przechodzenie w rekurencyjnym realizacji (użyć wiersza „alternate czas” powyżej zamiast pierwszej linii „Praca”), a nie zbyt trudne, jeśli używasz jawne stos, ale zostawię to jako ćwiczenie.
A, B, D, C, E, F
- pierwsza prezentowana), infix ( D, B, A, E, C, F
- używany do sortowania: dodaj jako drzewo AVL, a następnie przeczytaj infix) lub postfix ( D, B, E, F, C, A
prezentowana alternatywa) traversal. Nazwy są podane na podstawie pozycji, w której przetwarzasz root. Należy zauważyć, że wrostek ma sens tylko w przypadku drzew binarnych. @batbrat to są imiona ... biorąc pod uwagę czas odkąd zapytałeś, prawdopodobnie już wiesz.
Ten obraz powinien dać ci wyobrażenie o kontekście, w którym używane są słowa szerokość i głębokość .
Algorytm wyszukiwania w głąb działa tak, jakby chciał jak najszybciej oddalić się od punktu początkowego.
Zwykle używa znaku a, Stack
aby zapamiętać, dokąd ma się udać, gdy osiągnie ślepy zaułek.
Zasady, których należy przestrzegać: Wepchnij pierwszy wierzchołek A do Stack
Kod 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;
}
Zastosowania : Przeszukiwanie w głąb jest często używane w symulacjach gier (i sytuacji podobnych do gier w świecie rzeczywistym). W typowej grze możesz wybrać jedną z kilku możliwych akcji. Każdy wybór prowadzi do dalszych wyborów, z których każdy prowadzi do dalszych wyborów i tak dalej, do ciągle rozszerzającego się wykresu możliwości w kształcie drzewa.
Queue
.Kod 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;
}
Zastosowania : Przeszukiwanie wszerz najpierw znajduje wszystkie wierzchołki oddalone o jedną krawędź od punktu początkowego, następnie wszystkie wierzchołki oddalone o dwie krawędzie i tak dalej. Jest to przydatne, jeśli próbujesz znaleźć najkrótszą ścieżkę od początkowego wierzchołka do danego wierzchołka.
Miejmy nadzieję, że to powinno wystarczyć do zrozumienia wyszukiwań wszerz i najpierw w głąb. Do dalszej lektury polecam rozdział Wykresy z doskonałej książki Roberta Lafore'a o strukturach danych.
Biorąc pod uwagę to drzewo binarne:
Pierwsze przejście szerokości:
przechodzenie przez każdy poziom od lewej do prawej.
„Jestem G, moje dzieci to D i ja, moje wnuki to B, E, H i K, a ich wnuki to 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
Pierwsze przejście w głąb:
przemierzanie nie jest wykonywane jednocześnie na całych poziomach. Zamiast tego, przemierzanie nurkuje najpierw w GŁĘBOKOŚCI (od korzenia do liścia) drzewa. Jest to jednak nieco bardziej złożone niż po prostu w górę iw dół.
Istnieją trzy metody:
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
Użycie (aka, dlaczego nas to obchodzi):
bardzo podobało mi się to proste wyjaśnienie Quora dotyczące metod przechodzenia przez głębokość na początku i ich powszechnego stosowania:
„Przechodzenie na zamówienie wypisze wartości [w kolejności dla BST (drzewo wyszukiwania binarnego)] "
" Przechodzenie w przedsprzedaży służy do tworzenia kopii [drzewa wyszukiwania binarnego]. "
„Przechodzenie po zamówieniu służy do usuwania [drzewa wyszukiwania binarnego]”.
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing
Myślę, że byłoby interesujące napisać oba z nich w taki sposób, że tylko zmiana niektórych linii kodu daje jeden algorytm lub drugi, dzięki czemu zobaczysz, że twój dillema nie jest tak silny, jak się wydaje na początku .
Osobiście podoba mi się interpretacja BFS jako zalewania krajobrazu: najpierw zostaną zalane obszary na niskich wysokościach, a dopiero potem obszary na dużych wysokościach. Jeśli wyobrazisz sobie wysokości krajobrazowe jako izolinie, jakie widzimy w podręcznikach geografii, łatwo zauważyć, że BFS wypełnia cały obszar w tym samym izolinie w tym samym czasie, tak jak w przypadku fizyki. Zatem interpretacja wysokości jako odległości lub skalowanego kosztu daje dość intuicyjne wyobrażenie o algorytmie.
Mając to na uwadze, możesz łatwo dostosować ideę wyszukiwania wszerz, aby łatwo znaleźć minimalne drzewo rozpinające, najkrótszą ścieżkę, a także wiele innych algorytmów minimalizacji.
Nie widziałem jeszcze żadnej intuicyjnej interpretacji DFS (tylko standardowa o labiryncie, ale nie jest tak potężna jak BFS i zalanie), więc wydaje mi się, że BFS wydaje się lepiej korelować ze zjawiskami fizycznymi opisanymi powyżej, podczas gdy DFS lepiej koreluje z wyborami dillema w systemach racjonalnych (np. Ludzie lub komputery decydujące, który ruch wykonać w grze w szachy lub wyjść z labiryntu).
Tak więc dla mnie różnica polega na tym, które zjawisko naturalne najlepiej pasuje do ich modelu propagacji (poprzecznego) w prawdziwym życiu.