Quando si attraversa un albero / grafico qual è la differenza tra Breadth First e Depth first? Qualsiasi esempio di codifica o pseudocodice sarebbe fantastico.
Quando si attraversa un albero / grafico qual è la differenza tra Breadth First e Depth first? Qualsiasi esempio di codifica o pseudocodice sarebbe fantastico.
Risposte:
Questi due termini distinguono tra due diversi modi di camminare su un albero.
Probabilmente è più semplice esibire la differenza. Considera l'albero:
A
/ \
B C
/ / \
D E F
Una prima traversata approfondita visiterebbe i nodi in questo ordine
A, B, D, C, E, F
Si noti che si scende fino in fondo una gamba prima di proseguire .
Una prima traversata ampia visiterebbe il nodo in questo ordine
A, B, C, D, E, F
Qui lavoriamo fino in fondo ogni livello prima di scendere.
(Nota che c'è qualche ambiguità negli ordini trasversali, e ho barato per mantenere l'ordine di "lettura" ad ogni livello dell'albero. In entrambi i casi potrei arrivare a B prima o dopo C, e allo stesso modo potrei arrivare a E prima o dopo F. Questo può o non può importare, dipende dalla tua applicazione ...)
Entrambi i tipi di attraversamento possono essere raggiunti con lo pseudocodice:
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
La differenza tra i due ordini trasversali sta nella scelta di Container
.
Sembra l'implementazione ricorsiva
ProcessNode(Node)
Work on the payload Node
Foreach child of Node
ProcessNode(child)
/* Alternate time to work on the payload Node (see below) */
La ricorsione termina quando si raggiunge un nodo che non ha figli, quindi si garantisce che finisca per grafici finiti e aciclici.
A questo punto, ho ancora tradito un po '. Con un po 'di intelligenza puoi anche lavorare sui nodi in questo ordine:
D, B, E, F, C, A
che è una variazione di profondità in primo luogo, in cui non faccio il lavoro su ciascun nodo fino a quando non risalgo l'albero. Ho comunque visitato i nodi superiori sulla strada per trovare i loro figli.
Questo attraversamento è abbastanza naturale nell'implementazione ricorsiva (usa la riga "Tempo alternativo" sopra invece della prima riga "Lavoro"), e non troppo difficile se usi uno stack esplicito, ma lo lascerò come un esercizio.
A, B, D, C, E, F
- il primo presentato), infisso ( D, B, A, E, C, F
- usato per l'ordinamento: aggiungere come un albero AVL quindi leggere infisso) o postfisso ( D, B, E, F, C, A
l'alternativa presentata) traversal. I nomi sono dati dalla posizione in cui si elabora la radice. Va notato che infix ha davvero senso solo per gli alberi binari. @batbrat quelli sono i nomi ... visto il tempo da quando l'hai chiesto, probabilmente lo sai già.
Questa immagine dovrebbe darti l'idea del contesto in cui vengono usate le parole ampiezza e profondità .
L'algoritmo di ricerca in profondità agisce come se volesse allontanarsi il più rapidamente possibile dal punto di partenza.
Di solito usa a Stack
per ricordare dove dovrebbe andare quando raggiunge un vicolo cieco.
Regole da seguire: spingere il primo vertice A sul Stack
Codice 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;
}
Applicazioni : le ricerche in base alla profondità vengono spesso utilizzate nelle simulazioni di giochi (e situazioni simili al gioco nel mondo reale). In un gioco tipico puoi scegliere una delle diverse azioni possibili. Ogni scelta porta a ulteriori scelte, ognuna delle quali porta a ulteriori scelte, e così via in un grafico delle possibilità a forma di albero in continua espansione.
Queue
.Codice 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;
}
Applicazioni : la ricerca in ampiezza prima trova prima tutti i vertici che si trovano a un bordo dal punto iniziale, quindi tutti i vertici che si trovano a due bordi di distanza e così via. Questo è utile se stai cercando di trovare il percorso più breve dal vertice iniziale a un dato vertice.
Speriamo che ciò sia sufficiente per comprendere le ricerche Breadth-First e Depth-First. Per ulteriori letture consiglierei il capitolo Graphs da un eccellente libro sulle strutture di dati di Robert Lafore.
Dato questo albero binario:
Larghezza prima traversata:
attraversa ogni livello da sinistra a destra.
"Sono G, i miei figli sono D e io, i miei nipoti sono B, E, H e K, i loro nipoti sono 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
Profondità prima traversata:
traversata non viene eseguita ATTRAVERSO interi livelli alla volta. Invece, l'attraversamento si tuffa per primo nella PROFONDITÀ (dalla radice alla foglia) dell'albero. Tuttavia, è un po 'più complesso che semplicemente su e giù.
Esistono tre metodi:
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
Uso (alias, perché ci interessa):
mi è davvero piaciuta questa semplice spiegazione di Quora dei metodi Depth First Traversal e di come vengono comunemente utilizzati:
"In-Order Traversal stamperà i valori [in ordine per il BST (albero binario di ricerca)] "
" L'attraversamento pre-ordine viene utilizzato per creare una copia dell'albero [albero di ricerca binario]. "
"Traversal postorder viene utilizzato per eliminare [albero di ricerca binario]."
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing
Penso che sarebbe interessante scrivere entrambi in un modo che solo cambiando alcune righe di codice ti darebbe un algoritmo o l'altro, in modo che vedrai che il tuo dillema non è così forte come sembra all'inizio .
Personalmente mi piace l'interpretazione di BFS come inondazione di un paesaggio: le aree a bassa quota verranno inondate per prime, e solo dopo le aree ad alta quota seguiranno. Se immagini le altitudini del paesaggio come isoline come vediamo nei libri di geografia, è facile vedere che BFS riempie tutta l'area sotto lo stesso isoline allo stesso tempo, proprio come questo sarebbe con la fisica. Pertanto, interpretare le altitudini come distanza o costo in scala dà un'idea abbastanza intuitiva dell'algoritmo.
Con questo in mente, puoi facilmente adattare l'idea alla base della prima ricerca per trovare facilmente l'albero di spanning minimo, il percorso più breve e anche molti altri algoritmi di minimizzazione.
Non ho ancora visto alcuna interpretazione intuitiva di DFS (solo quella standard sul labirinto, ma non è potente come quella BFS e inondazioni), quindi per me sembra che BFS sembra correlare meglio con i fenomeni fisici come descritto sopra, mentre Il DFS si correla meglio con le scelte dillema sui sistemi razionali (cioè persone o computer che decidono quale mossa fare una partita a scacchi o uscire da un labirinto).
Quindi, per me la differenza tra bugie su quale fenomeno naturale si adatta meglio al loro modello di propagazione (trasversale) nella vita reale.