J'ai un arbre en entrée de la première recherche en largeur et je veux savoir à quel niveau l'algorithme progresse à quel niveau il se trouve?
# Breadth First Search Implementation
graph = {
'A':['B','C','D'],
'B':['A'],
'C':['A','E','F'],
'D':['A','G','H'],
'E':['C'],
'F':['C'],
'G':['D'],
'H':['D']
}
def breadth_first_search(graph,source):
"""
This function is the Implementation of the breadth_first_search program
"""
# Mark each node as not visited
mark = {}
for item in graph.keys():
mark[item] = 0
queue, output = [],[]
# Initialize an empty queue with the source node and mark it as explored
queue.append(source)
mark[source] = 1
output.append(source)
# while queue is not empty
while queue:
# remove the first element of the queue and call it vertex
vertex = queue[0]
queue.pop(0)
# for each Edge from the vertex do the following
for vrtx in graph[vertex]:
# If the vertex is unexplored
if mark[vrtx] == 0:
queue.append(vrtx) # mark it as explored
mark[vrtx] = 1 # and append it to the queue
output.append(vrtx) # fill the output vector
return output
print breadth_first_search(graph, 'A')
Il faut l’arbre comme graphe d’entrée, ce que je veux, c’est qu’à chaque itération, il indique le niveau en cours de traitement.
Vous n'avez pas besoin d'utiliser une file d'attente supplémentaire ni de faire des calculs compliqués pour obtenir ce que vous voulez faire. Cette idée est très simple.
Cela n'utilise aucun espace supplémentaire autre que la file d'attente utilisée pour BFS.
L'idée que je vais utiliser est d'ajouter null
à la fin de chaque niveau. Ainsi, le nombre de valeurs nulles que vous avez rencontrées +1 correspond à la profondeur à laquelle vous vous trouvez. (bien sûr, après la résiliation, c'est juste level
).
int level = 0;
Queue <Node> queue = new LinkedList<>();
queue.add(root);
queue.add(null);
while(!queue.isEmpty()){
Node temp = queue.poll();
if(temp == null){
level++;
queue.add(null);
if(queue.peek() == null) break;// You are encountering two consecutive `nulls` means, you visited all the nodes.
else continue;
}
if(temp.right != null)
queue.add(temp.right);
if(temp.left != null)
queue.add(temp.left);
}
Maintenir une file d'attente stockant la profondeur du nœud correspondant dans la file d'attente BFS. Exemple de code pour votre information:
queue bfsQueue, depthQueue;
bfsQueue.Push(firstNode);
depthQueue.Push(0);
while (!bfsQueue.empty()) {
f = bfsQueue.front();
depth = depthQueue.front();
bfsQueue.pop(), depthQueue.pop();
for (every node adjacent to f) {
bfsQueue.Push(node), depthQueue.Push(depth+1);
}
}
Cette méthode est simple et naïve; pour O(1), vous aurez peut-être besoin de la réponse postée par @stolen_leaves.
Si votre arbre est parfaitement équilibré (chaque nœud a le même nombre d’enfants), il existe une solution simple et élégante avec une complexité temporelle O(1) et complexe O(1) spatiale. Le cas d'utilisation principal dans lequel je trouve cela utile est de parcourir un arbre binaire, bien qu'il soit trivialement adaptable à d'autres tailles d'arbres.
L’essentiel à retenir ici est que chaque niveau d’un arbre binaire contient exactement le double de la quantité de nœuds par rapport au niveau précédent. Cela nous permet de calculer le nombre total de nœuds dans n’importe quel arbre compte tenu de la profondeur de l’arbre. Par exemple, considérons l’arbre suivant:
Cet arbre a une profondeur de 3 et 7 noeuds totaux. Nous n'avons pas besoin de compter le nombre de nœuds pour comprendre cela cependant. Nous pouvons calculer ceci dans O(1) temps avec la formule suivante: 2 ^ d - 1 = N, où d
est la profondeur et N
est le nombre total de nœuds. (Dans un arbre ternaire, cela correspond à 3 ^ d - 1 = N et dans un arbre où chaque nœud a K enfants, il s'agit de K ^ d - 1 = N). Donc dans ce cas, 2 ^ 3 - 1 = 7.
Pour garder une trace de la profondeur tout en effectuant une première recherche approfondie, nous devons simplement inverser ce calcul. Alors que la formule ci-dessus nous permet de résoudre pour N
donnée d
, nous souhaitons en fait résoudre pour d
donnée N
. Par exemple, disons que nous évaluons le 5ème noeud. Pour déterminer la profondeur sur laquelle se trouve le cinquième nœud, prenons l'équation suivante: 2 ^ d - 1 = 5, puis résolvez simplement pour d
, qui est l'algèbre de base:
Si d
s'avère être autre chose qu'un nombre entier, arrondissez simplement vers le haut (le dernier nœud dans une ligne est toujours un nombre entier). Dans cet esprit, je propose l’algorithme suivant pour identifier la profondeur d’un nœud donné dans un arbre binaire lors du premier parcours en largeur:
visited
égale à 0.visited
de 1.visited
est incrémenté, calculez la profondeur du nœud comme suit: depth = round_up(log2(visited + 1))
Vous pouvez également utiliser une table de hachage pour mapper chaque nœud à son niveau de profondeur, bien que cela augmente la complexité de l'espace à O (n). Voici une implémentation PHP de cet algorithme:
<?php
$tree = [
['A', [1,2]],
['B', [3,4]],
['C', [5,6]],
['D', [7,8]],
['E', [9,10]],
['F', [11,12]],
['G', [13,14]],
['H', []],
['I', []],
['J', []],
['K', []],
['L', []],
['M', []],
['N', []],
['O', []],
];
function bfs($tree) {
$queue = new SplQueue();
$queue->enqueue($tree[0]);
$visited = 0;
$depth = 0;
$result = [];
while ($queue->count()) {
$visited++;
$node = $queue->dequeue();
$depth = ceil(log($visited+1, 2));
$result[$depth][] = $node[0];
if (!empty($node[1])) {
foreach ($node[1] as $child) {
$queue->enqueue($tree[$child]);
}
}
}
print_r($result);
}
bfs($tree);
Quelles impressions:
Array
(
[1] => Array
(
[0] => A
)
[2] => Array
(
[0] => B
[1] => C
)
[3] => Array
(
[0] => D
[1] => E
[2] => F
[3] => G
)
[4] => Array
(
[0] => H
[1] => I
[2] => J
[3] => K
[4] => L
[5] => M
[6] => N
[7] => O
)
)
Essayez de jeter un oeil à ce post. Il garde la trace de la profondeur en utilisant la variable currentDepth
https://stackoverflow.com/a/16923440/3114945
Pour votre implémentation, gardez une trace du nœud le plus à gauche et d'une variable pour la profondeur. Chaque fois que le nœud le plus à gauche est sorti de la file d'attente, vous savez que vous atteignez un nouveau niveau et que vous incrémentez la profondeur.
Ainsi, votre racine est la leftMostNode
au niveau 0. Ensuite, l’enfant le plus à gauche est la leftMostNode
. Dès que vous l'atteignez, il passe au niveau 1. L'enfant le plus à gauche de ce nœud est le prochain leftMostNode
et ainsi de suite.
Avec ce code Python, vous pouvez conserver la profondeur de chaque nœud à partir de la racine en augmentant la profondeur uniquement après avoir rencontré un nœud d'une nouvelle profondeur dans la file d'attente.
queue = deque()
marked = set()
marked.add(root)
queue.append((root,0))
depth = 0
while queue:
r,d = queue.popleft()
if d > depth: # increase depth only when you encounter the first node in the next depth
depth += 1
for node in edges[r]:
if node not in marked:
marked.add(node)
queue.append((node,depth+1))
En Java, ce serait quelque chose comme ceci ... L'idée est de regarder le parent pour décider de la profondeur.
//Maintain depth for every node based on its parent's depth
Map<Character,Integer> depthMap=new HashMap<>();
queue.add('A');
depthMap.add('A',0); //this is where you start your search
while(!queue.isEmpty())
{
Character parent=queue.remove();
List<Character> children=adjList.get(parent);
for(Character c:children)
{
depthMap.add(c,depthMap.get(parent)+1);//parent's depth + 1
}
}