freeCodeCamp/curriculum/challenges/italian/10-coding-interview-prep/data-structures/breadth-first-search.md

6.5 KiB

id title challengeType forumTopicId dashedName
587d825c367417b2b2512c90 Breadth-First Search 1 301622 breadth-first-search

--description--

Finora, abbiamo imparato diversi modi per creare rappresentazioni di grafi. E adesso? Una domanda naturale da porsi è quali sono le distanze tra due nodi qualsiasi nel grafo? Qui entrano in gioco gli algoritmi di attraversamento di grafi.

Gli algoritmi di attraversamento sono algoritmi per attraversare o visitare nodi in un grafo. Un tipo di algoritmo di attraversamento è l'algoritmo Breadth-first Search (di ricerca in ampiezza).

Questo algoritmo inizia da un nodo e visita tutti i suoi vicini che sono ad un arco di distanza. Poi continua a visitare ciascuno dei loro vicini e così via fino a quando tutti i nodi sono stati raggiunti.

Una struttura dati importante che aiuterà ad implementare l'algoritmo di ricerca in ampiezza è la coda. Questa è un array dove è possibile aggiungere elementi ad una estremità e rimuovere elementi dall'altra estremità. Essa è nota anche come una struttura di dati FIFO o First-In-First-Out (NdT: il primo a entrare è il primo a uscire).

Visualmente, questo è ciò che l'algoritmo sta facendo. Algoritmo Breadth-first Search che si muove attraverso un albero

L'ombreggiatura grigia rappresenta un nodo che viene aggiunto alla coda e l'ombreggiatura nera rappresenta un nodo che viene rimosso dalla coda. Vedi come ogni volta che un nodo viene rimosso dalla coda (il nodo diventa nero), tutti i vicini vengono aggiunti alla coda (il nodo diventa grigio).

Per implementare questo algoritmo, dovrai inserire una struttura grafo e un nodo da cui vuoi iniziare.

Innanzitutto, dovrai essere consapevole delle distanze (o del numero di archi di distanza) dal nodo iniziale. Ti consigliamo di inizializzare tutte le distanze con un numero elevato, come Infinity. Questo impedisce problemi di conteggio per quando un nodo potrebbe non essere raggiungibile dal nodo iniziale. Successivamente, vorrai andare dal nodo iniziale ai suoi vicini. Questi vicini sono a un arco di distanza e a questo punto dovresti aggiungere un'unità di distanza alle distanze di cui stai tenendo traccia.

--instructions--

Scrivi una funzione bfs() che prende un grafo a matrice di adiacenza (un array bidimensionale) e l'etichetta di un nodo radice come parametri. L'etichetta del nodo sarà solo il valore intero del nodo tra 0 e n - 1, dove n è il numero totale di nodi nel grafico.

La tua funzione produrrà coppie chiave-valore di un oggetto JavaScript con il nodo e la sua distanza dalla radice. Se il nodo non può essere raggiunto, dovrebbe avere una distanza di Infinity.

--hints--

Il grafico in ingresso [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]] con un nodo iniziale di 1 dovrebbe restituire {0: 1, 1: 0, 2: 1, 3: 2}

assert(
  (function () {
    var graph = [
      [0, 1, 0, 0],
      [1, 0, 1, 0],
      [0, 1, 0, 1],
      [0, 0, 1, 0]
    ];
    var results = bfs(graph, 1);
    return isEquivalent(results, { 0: 1, 1: 0, 2: 1, 3: 2 });
  })()
);

Il grafico in ingresso [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]] con un nodo iniziale di 1 dovrebbe restituire {0: 1, 1: 0, 2: 1, 3: Infinity}

assert(
  (function () {
    var graph = [
      [0, 1, 0, 0],
      [1, 0, 1, 0],
      [0, 1, 0, 0],
      [0, 0, 0, 0]
    ];
    var results = bfs(graph, 1);
    return isEquivalent(results, { 0: 1, 1: 0, 2: 1, 3: Infinity });
  })()
);

Il grafico in ingresso [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]] con un nodo iniziale di 0 dovrebbe restituire {0: 0, 1: 1, 2: 2, 3: 3}

assert(
  (function () {
    var graph = [
      [0, 1, 0, 0],
      [1, 0, 1, 0],
      [0, 1, 0, 1],
      [0, 0, 1, 0]
    ];
    var results = bfs(graph, 0);
    return isEquivalent(results, { 0: 0, 1: 1, 2: 2, 3: 3 });
  })()
);

Il grafo in ingresso [[0, 1], [1, 0]] con un nodo iniziale di 0 dovrebbe restituire {0: 0, 1: 1}

assert(
  (function () {
    var graph = [
      [0, 1],
      [1, 0]
    ];
    var results = bfs(graph, 0);
    return isEquivalent(results, { 0: 0, 1: 1 });
  })()
);

--seed--

--after-user-code--

// Source: http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html
function isEquivalent(a, b) {
    // Create arrays of property names
    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);
    // If number of properties is different,
    // objects are not equivalent
    if (aProps.length != bProps.length) {
        return false;
    }
    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];
        // If values of same property are not equal,
        // objects are not equivalent
        if (a[propName] !== b[propName]) {
            return false;
        }
    }
    // If we made it this far, objects
    // are considered equivalent
    return true;
}

--seed-contents--

function bfs(graph, root) {
  var nodesLen = {};

  return nodesLen;
};

var exBFSGraph = [
  [0, 1, 0, 0],
  [1, 0, 1, 0],
  [0, 1, 0, 1],
  [0, 0, 1, 0]
];
console.log(bfs(exBFSGraph, 3));

--solutions--

function bfs(graph, root) {
  var nodesLen = {};
  // Set all distances to infinity
  for (var i = 0; i < graph.length; i++) {
    nodesLen[i] = Infinity;
  }
  nodesLen[root] = 0; // ...except root node
  var queue = [root]; // Keep track of nodes to visit
  var current; // Current node traversing
  // Keep on going until no more nodes to traverse
  while (queue.length !== 0) {
    current = queue.shift();
    // Get adjacent nodes from current node
    var curConnected = graph[current]; // Get layer of edges from current
    var neighborIdx = []; // List of nodes with edges
    var idx = curConnected.indexOf(1); // Get first edge connection
    while (idx !== -1) {
      neighborIdx.push(idx); // Add to list of neighbors
      idx = curConnected.indexOf(1, idx + 1); // Keep on searching
    }
    // Loop through neighbors and get lengths
    for (var j = 0; j < neighborIdx.length; j++) {
      // Increment distance for nodes traversed
      if (nodesLen[neighborIdx[j]] === Infinity) {
        nodesLen[neighborIdx[j]] = nodesLen[current] + 1;
        queue.push(neighborIdx[j]); // Add new neighbors to queue
      }
    }
  }
  return nodesLen;
}