web-dev-qa-db-fra.com

Comment garder la profondeur dans la première recherche en largeur?

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.

13
functioncall

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);
     }
28
Karthik

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.

4
matrixit

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:

 enter image description here

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:

 enter image description here

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:

  1. Laissez la variable visited égale à 0.
  2. Chaque fois qu'un nœud est visité, incrémentez visited de 1.
  3. Chaque fois que 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
            )

    )
3
Matt Korostoff

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. 

3
stolen_leaves

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))
1
MROB

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

   }

}
0
developer747