mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-17 06:00:58 +00:00
build
This commit is contained in:
@@ -4,7 +4,7 @@ comments: true
|
||||
|
||||
# 9.3 Обход графа
|
||||
|
||||
Дерево представляет отношение "один ко многим", тогда как граф обладает большей свободой и может выражать произвольные отношения "многие ко многим". Поэтому дерево можно рассматривать как частный случай графа. Очевидно, что **операции обхода дерева также являются частным случаем операций обхода графа**.
|
||||
Дерево представляет отношение «один ко многим», тогда как граф обладает большей свободой и может выражать произвольные отношения «многие ко многим». Поэтому дерево можно рассматривать как частный случай графа. Очевидно, что **операции обхода дерева также являются частным случаем операций обхода графа**.
|
||||
|
||||
И графы, и деревья требуют применения алгоритмов обхода. Способы обхода графа также делятся на два типа: <u>обход в ширину</u> и <u>обход в глубину</u>.
|
||||
|
||||
@@ -18,7 +18,7 @@ comments: true
|
||||
|
||||
### 1. Реализация алгоритма
|
||||
|
||||
BFS обычно реализуется с помощью очереди, код приведен ниже. Очередь обладает свойством "первым пришел - первым вышел", что хорошо соответствует идее BFS "от ближнего к дальнему".
|
||||
BFS обычно реализуется с помощью очереди, код приведен ниже. Очередь обладает свойством «первым пришел - первым вышел», что хорошо соответствует идее BFS «от ближнего к дальнему».
|
||||
|
||||
1. Поместить стартовую вершину обхода `startVet` в очередь и запустить цикл.
|
||||
2. На каждой итерации цикла извлекать вершину из головы очереди и записывать ее посещение, после чего добавлять все смежные вершины этой вершины в хвост очереди.
|
||||
@@ -480,7 +480,7 @@ BFS обычно реализуется с помощью очереди, код
|
||||
<div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=from%20collections%20import%20deque%0A%0Aclass%20Vertex%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%27Vertex%27%5D%3A%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0Adef%20graph_bfs%28graph%3A%20GraphAdjList%2C%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20visited%20%3D%20set%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%20%20que%20%3D%20deque%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%20%20while%20len%28que%29%20%3E%200%3A%0A%20%20%20%20%20%20%20%20vet%20%3D%20que.popleft%28%29%0A%20%20%20%20%20%20%20%20res.append%28vet%29%0A%20%20%20%20%20%20%20%20for%20adj_vet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20adj_vet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%20%20%20%20que.append%28adj_vet%29%0A%20%20%20%20%20%20%20%20%20%20%20%20visited.add%28adj_vet%29%0A%20%20%20%20return%20res%0A%27Driver%20Code%27%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B0%2C%201%2C%202%2C%203%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B4%5D%5D%2C%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20del%20edges%0A%20%20%20%20res%20%3D%20graph_bfs%28graph%2C%20v%5B0%5D%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=131&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
|
||||
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=from%20collections%20import%20deque%0A%0Aclass%20Vertex%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%27Vertex%27%5D%3A%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0Adef%20graph_bfs%28graph%3A%20GraphAdjList%2C%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20visited%20%3D%20set%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%20%20que%20%3D%20deque%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%20%20while%20len%28que%29%20%3E%200%3A%0A%20%20%20%20%20%20%20%20vet%20%3D%20que.popleft%28%29%0A%20%20%20%20%20%20%20%20res.append%28vet%29%0A%20%20%20%20%20%20%20%20for%20adj_vet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20adj_vet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%20%20%20%20que.append%28adj_vet%29%0A%20%20%20%20%20%20%20%20%20%20%20%20visited.add%28adj_vet%29%0A%20%20%20%20return%20res%0A%27Driver%20Code%27%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B0%2C%201%2C%202%2C%203%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B4%5D%5D%2C%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20del%20edges%0A%20%20%20%20res%20%3D%20graph_bfs%28graph%2C%20v%5B0%5D%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=131&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Во весь экран ></a></div>
|
||||
|
||||
Код сравнительно абстрактен, поэтому рекомендуется сверяться с рисунками ниже для лучшего понимания.
|
||||
Код сравнительно абстрактен, поэтому для лучшего понимания рекомендуется сопоставлять его с тем, что показано на рисунке 9-10.
|
||||
|
||||
=== "<1>"
|
||||
{ class="animation-figure" }
|
||||
@@ -519,11 +519,11 @@ BFS обычно реализуется с помощью очереди, код
|
||||
|
||||
!!! question "Является ли последовательность обхода в ширину единственной?"
|
||||
|
||||
Нет. Обход в ширину требует только соблюдения порядка "от ближнего к дальнему", **а порядок обхода нескольких вершин на одинаковом расстоянии может произвольно меняться**. Например, на рисунке 9-10 можно поменять местами порядок посещения вершин $1$ и $3$ , а вершины $2$, $4$, $6$ также можно переставлять произвольно.
|
||||
Нет. Обход в ширину требует только соблюдения порядка «от ближнего к дальнему», **а порядок обхода нескольких вершин на одинаковом расстоянии может произвольно меняться**. Например, на рисунке 9-10 можно поменять местами порядок посещения вершин $1$ и $3$ , а вершины $2$, $4$, $6$ также можно переставлять произвольно.
|
||||
|
||||
### 2. Анализ сложности
|
||||
|
||||
**Временная сложность**: все вершины по одному разу помещаются в очередь и извлекаются из нее, что требует $O(|V|)$ времени; при обходе смежных вершин, поскольку граф неориентированный, все ребра будут посещены по $2$ раза, что требует $O(2|E|)$ времени; в сумме получается $O(|V| + |E|)$ .
|
||||
**Временная сложность**: все вершины по одному разу помещаются в очередь и извлекаются из нее, что требует $O(|V|)$ времени. При обходе смежных вершин, поскольку граф неориентированный, все ребра будут посещены по $2$ раза, что требует $O(2|E|)$ времени. В сумме получается $O(|V| + |E|)$ .
|
||||
|
||||
**Пространственная сложность**: список `res` , хеш-множество `visited` и очередь `que` в худшем случае могут содержать до $|V|$ вершин, поэтому требуется $O(|V|)$ памяти.
|
||||
|
||||
@@ -537,7 +537,7 @@ BFS обычно реализуется с помощью очереди, код
|
||||
|
||||
### 1. Реализация алгоритма
|
||||
|
||||
Такой алгоритмический шаблон "дойти до конца и вернуться" обычно реализуется через рекурсию. Подобно обходу в ширину, в обходе в глубину мы также используем хеш-множество `visited` для записи уже посещенных вершин и тем самым избегаем повторного посещения.
|
||||
Такой алгоритмический шаблон «дойти до конца и вернуться» обычно реализуется через рекурсию. Подобно обходу в ширину, в обходе в глубину мы также используем хеш-множество `visited` для записи уже посещенных вершин и тем самым избегаем повторного посещения.
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -940,12 +940,12 @@ BFS обычно реализуется с помощью очереди, код
|
||||
<div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=class%20Vertex%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%27Vertex%27%5D%3A%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0Adef%20dfs%28graph%3A%20GraphAdjList%2C%20visited%3A%20set%5BVertex%5D%2C%20res%3A%20list%5BVertex%5D%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20res.append%28vet%29%0A%20%20%20%20visited.add%28vet%29%0A%20%20%20%20for%20adjVet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20%20%20if%20adjVet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20dfs%28graph%2C%20visited%2C%20res%2C%20adjVet%29%0A%0Adef%20graph_dfs%28graph%3A%20GraphAdjList%2C%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20visited%20%3D%20set%5BVertex%5D%28%29%0A%20%20%20%20dfs%28graph%2C%20visited%2C%20res%2C%20start_vet%29%0A%20%20%20%20return%20res%0A%27Driver%20Code%27%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B0%2C%201%2C%202%2C%203%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B4%5D%5D%2C%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20res%20%3D%20graph_dfs%28graph%2C%20v%5B0%5D%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=130&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
|
||||
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=class%20Vertex%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%27Vertex%27%5D%3A%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0Adef%20dfs%28graph%3A%20GraphAdjList%2C%20visited%3A%20set%5BVertex%5D%2C%20res%3A%20list%5BVertex%5D%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20res.append%28vet%29%0A%20%20%20%20visited.add%28vet%29%0A%20%20%20%20for%20adjVet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20%20%20if%20adjVet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20dfs%28graph%2C%20visited%2C%20res%2C%20adjVet%29%0A%0Adef%20graph_dfs%28graph%3A%20GraphAdjList%2C%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20visited%20%3D%20set%5BVertex%5D%28%29%0A%20%20%20%20dfs%28graph%2C%20visited%2C%20res%2C%20start_vet%29%0A%20%20%20%20return%20res%0A%27Driver%20Code%27%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B0%2C%201%2C%202%2C%203%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B4%5D%5D%2C%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20res%20%3D%20graph_dfs%28graph%2C%20v%5B0%5D%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=130&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Во весь экран ></a></div>
|
||||
|
||||
Алгоритмический процесс обхода в глубину показан на рисунках ниже.
|
||||
Алгоритмический процесс обхода в глубину показан на рисунке 9-12.
|
||||
|
||||
- **Прямая пунктирная линия обозначает нисходящую рекурсию** , то есть запуск нового рекурсивного метода для посещения новой вершины.
|
||||
- **Изогнутая пунктирная линия обозначает восходящую рекурсию** , то есть данный рекурсивный метод завершился и управление вернулось туда, откуда он был вызван.
|
||||
|
||||
Чтобы лучше понять алгоритм, рекомендуется совместить рисунки ниже с кодом и мысленно проследить весь процесс DFS, включая моменты запуска и возврата каждого рекурсивного вызова.
|
||||
Чтобы лучше понять алгоритм, рекомендуется сопоставить код с тем, что показано на рисунке 9-12, и мысленно проследить весь процесс DFS, включая моменты запуска и возврата каждого рекурсивного вызова.
|
||||
|
||||
=== "<1>"
|
||||
{ class="animation-figure" }
|
||||
@@ -985,11 +985,11 @@ BFS обычно реализуется с помощью очереди, код
|
||||
!!! question "Является ли последовательность обхода в глубину единственной?"
|
||||
|
||||
Как и в случае обхода в ширину, последовательность DFS тоже не является единственной. Для заданной вершины допустимо сначала углубиться в любое направление, то есть порядок смежных вершин может быть произвольным, и все такие варианты будут корректными обходами в глубину.
|
||||
|
||||
Если взять в качестве примера обход дерева, то варианты "корень $\rightarrow$ лево $\rightarrow$ право", "лево $\rightarrow$ корень $\rightarrow$ право" и "лево $\rightarrow$ право $\rightarrow$ корень" соответствуют прямому, симметричному и обратному обходам соответственно. Они показывают три разных приоритета обхода, но все они относятся к обходу в глубину.
|
||||
|
||||
Если взять в качестве примера обход дерева, то варианты «корень $\rightarrow$ лево $\rightarrow$ право», «лево $\rightarrow$ корень $\rightarrow$ право» и «лево $\rightarrow$ право $\rightarrow$ корень» соответствуют прямому, симметричному и обратному обходам соответственно. Они показывают три разных приоритета обхода, но все они относятся к обходу в глубину.
|
||||
|
||||
### 2. Анализ сложности
|
||||
|
||||
**Временная сложность**: все вершины будут посещены по $1$ разу, что требует $O(|V|)$ времени; все ребра будут посещены по $2$ раза, что требует $O(2|E|)$ времени; суммарно получается $O(|V| + |E|)$ .
|
||||
**Временная сложность**: все вершины будут посещены по $1$ разу, что требует $O(|V|)$ времени. Все ребра будут посещены по $2$ раза, что требует $O(2|E|)$ времени. Суммарно получается $O(|V| + |E|)$ .
|
||||
|
||||
**Пространственная сложность**: число вершин в списке `res` и хеш-множестве `visited` в худшем случае достигает $|V|$ , максимальная глубина рекурсии тоже равна $|V|$ , поэтому требуется $O(|V|)$ памяти.
|
||||
|
||||
Reference in New Issue
Block a user