Jak prześledzić ścieżkę przeszukiwania wszerz, tak jak w poniższym przykładzie:
Jeśli szukasz klucza 11
, zwróć najkrótszą listę łączącą od 1 do 11.
[1, 4, 7, 11]
python
algorithm
graph
breadth-first-search
Christopher Markieta
źródło
źródło
Odpowiedzi:
Najpierw powinieneś spojrzeć na http://en.wikipedia.org/wiki/Breadth-first_search .
Poniżej znajduje się szybka realizacja, w której użyłem listy do reprezentowania kolejki ścieżek.
Innym podejściem byłoby zachowanie odwzorowania z każdego węzła na jego rodzica, a podczas inspekcji sąsiedniego węzła, zarejestrowanie jego rodzica. Po zakończeniu wyszukiwania po prostu prześledź wstecz zgodnie z mapowaniem nadrzędnym.
Powyższe kody są oparte na założeniu, że nie ma cykli.
źródło
node==end
), dodaj ją do innej listy, która będzie zawierać wszystkie znalezione ścieżki, a następniecontinue
zamiastreturn
. Jeśli używasz odwiedzanego zestawu, aby zapobiec cyklom, nie dodawaj nigdy węzła końcowego do odwiedzanego zestawu (w przeciwnym razie tylko jedna ścieżka może mieć ten węzeł końcowy).Bardzo podobała mi się pierwsza odpowiedź qiao! Jedyne, czego tu brakuje, to oznaczyć wierzchołki jako odwiedzone.
Dlaczego musimy to zrobić?
Wyobraźmy sobie, że jest inny węzeł numer 13 połączony z węzłem 11. Teraz naszym celem jest znalezienie węzła 13.
Po krótkim uruchomieniu kolejka będzie wyglądać następująco:
Zauważ, że istnieją DWIE ścieżki z numerem węzła 10 na końcu.
Co oznacza, że ścieżki z węzła numer 10 zostaną sprawdzone dwukrotnie. W tym przypadku nie wygląda to tak źle, ponieważ węzeł numer 10 nie ma żadnych dzieci .. Ale może być naprawdę zły (nawet tutaj sprawdzimy ten węzeł dwa razy bez powodu ..)
Węzeł numer 13 nie jest w te ścieżki, aby program nie powrócił przed dotarciem do drugiej ścieżki z węzłem numer 10 na końcu .. i sprawdzimy to ponownie ..
Brakuje nam tylko zestawu do oznaczania odwiedzanych węzłów i nie sprawdzania ich ponownie.
Oto kod qiao po modyfikacji:
Wynik programu będzie:
Bez zbędnych ponownych sprawdzeń.
źródło
collections.deque
dlaqueue
jak list.pop (0) ponieśćO(n)
ruchów pamięci. Ponadto, ze względu na potomność, jeśli chcesz wykonać DFS, po prostu ustawpath = queue.pop()
w którym przypadku zmiennaqueue
faktycznie zachowuje się jak astack
.Bardzo łatwy kod. Ciągle dołączasz ścieżkę za każdym razem, gdy odkryjesz węzeł.
źródło
Pomyślałem, że spróbuję to zakodować dla zabawy:
Jeśli chcesz cykli, możesz dodać to:
źródło
Podoba mi się zarówno pierwsza odpowiedź @Qiao, jak i dodatek @ Or. Ze względu na nieco mniej przetwarzania chciałbym dodać do odpowiedzi Ora.
W odpowiedzi @ Or, śledzenie odwiedzonego węzła jest świetne. Możemy także zezwolić programowi na wcześniejsze zakończenie pracy niż obecnie. W pewnym momencie pętli for
current_neighbour
będzie musiało byćend
, a kiedy to nastąpi, zostanie znaleziona najkrótsza ścieżka i program może powrócić.Zmodyfikowałbym metodę w następujący sposób, zwróć szczególną uwagę na pętlę for
Wynik i wszystko inne będzie takie samo. Jednak przetworzenie kodu zajmie mniej czasu. Jest to szczególnie przydatne na większych wykresach. Mam nadzieję, że to pomoże komuś w przyszłości.
źródło