L’algoritmo di Breadth First Search, o visita in ampiezza, visita i nodi di un grafo livello per livello come un onda che si espande. Ogni nodo viene raggiunto seguendo il percorso più breve dalla sorgente della visita.

L’implementazione ottima ha complessità temporale .

Nella sua implementazione più efficiente, la BFS fa uso di una queue come struttura dati di appoggio: durante ogni livello della visita i nodi vengono inseriti in essa, processati e espulsi (LIFO).

N.B.: In tutti questi algoritmi i grafi sono implementati con le liste di adiacenza.

La BFS si usa in:

Implementazioni

Con la lista che simula una coda

def bfs_array(grafo, nodo):
	n = len(grafo)
	visitati = [False] * n
	coda = [nodo]
	visitati[nodo] = True
	while coda:
		nodo_corrente = coda.pop(0) # costo O(n)
		for vicino in grafo[nodo]:
			if not visitati[nodo]:
				visitati[nodo] = True
				coda.append(y)
	return [nodo for nodo in range(n) if visitati[nodo]]

Con la lista che simula una coda, ma con la cancellazione logica

Si usa un indice testa che si sposta in avanti, simulando la rimozione degli elementi.

def bfs_array_logico(grafo, primo_nodo):
	n = len(grafo)
	visitati = [False] * n
	coda = [primo_nodo]
	testa = 0
	visitati[primo_nodo] = True
	while testa < len(coda):
		nodo_corrente = coda[testa]
		testa += 1
		for vicino in grafo[nodo_corrente]:
			if not visitati[nodo_corrente]:
				visitati[nodo_corrente] = True
				coda.append(vicino)
	return [nodo for nodo in range(n) if visitati[nodo]]

Con la deque di collections

from collections import deque
 
def bfs_deque(grafo, primo_nodo):
	n = len(grafo)
	visitati = [False] * n
	coda = deque()
	coda.append(primo_nodo)
	visitati[primo_nodo] = 1
	while coda:
		nodo_corrente = coda.popleft() # O(1)
		for vicino in grafo[nodo_corrente]:
			if not visitati[nodo_corrente]:
				visitati[nodo_corrente] = True
				coda.append(vicino)
	return [nodo for nodo in range(n) if visitati[nodo]]

Albero BFS

La BFS costruisce implicitamente l’albero BFS ovvero il sottoinsieme del grafo formato da tutti i nodi raggiungibili dalla sorgente e dagli archi usati per raggiungerli. È l’albero dei cammini minimi dalla sorgente della BFS.

Viene rappresentato con il vettore dei padri dove è il nodo da cui si è raggiunto per la prima volta. Per convenzione si usano:

  • se il nodo non è mai stato visitato.
  • (un cappio) per la radice della BFS.
def albero_bfs(grafo, nodo):
	n = len(grafo)
	vettore = [-1] * n
	vettore[nodo] = nodo
	coda = [nodo]
	testa = 0
	while testa < len(coda):
		nodo_corrente = coda[testa]
		testa += 1
		for vicino in grafo[nodo_corrente]:
			if vettore[vicino] == -1:
				vettore[vicino] = nodo_corrente
				coda.append(vicino)
	return vettore