From 385896c6a13414a4e923848e9efc12957179ce3c Mon Sep 17 00:00:00 2001 From: Yana Kalsina Date: Wed, 26 Nov 2025 21:48:03 +0300 Subject: [PATCH 1/4] Realised depth first search class --- .../depth_first_search_class.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/Depth_first_search/depth_first_search_class.py diff --git a/src/Depth_first_search/depth_first_search_class.py b/src/Depth_first_search/depth_first_search_class.py new file mode 100644 index 0000000..084f122 --- /dev/null +++ b/src/Depth_first_search/depth_first_search_class.py @@ -0,0 +1,42 @@ +class Graph: + def __init__(self, vertices: list[int], edges:list[tuple[int, int]]) -> None: + self.vertices = vertices + self.edges = edges + self.visited_vertices = list() + self.index = 0 + + def dfs(self) -> list[int]: + states = {"white": [v for v in self.vertices], + "grey": list(), + "black": list()} + # если я правильно поняла, вершина является посещенной, если она просто попала в список grey + def dfs_step(vertex): + states["grey"].append(vertex) + self.visited_vertices.append(vertex) + states["white"].remove(vertex) + for edge in self.edges: + if vertex == edge[0]: + if edge[1] in states["white"]: + dfs_step(edge[1]) + if vertex == edge[1]: + if edge[0] in states["white"]: + dfs_step(edge[0]) + states["black"].append(vertex) + states["grey"].remove(vertex) + for vertex in self.vertices: + if vertex in states["white"]: + dfs_step(vertex) + return self.visited_vertices + + def __iter__(self): + if self.visited_vertices == []: + self.visited_vertices = self.dfs() + self.index = 0 + return self + + def __next__(self): + if self.index >= len(self.visited_vertices): + raise StopIteration + vertex = self.visited_vertices[self.index] + self.index += 1 + return vertex \ No newline at end of file From f33a82a52755d4fca4b0b7a8b61cad5294de1309 Mon Sep 17 00:00:00 2001 From: Yana Kalsina Date: Wed, 26 Nov 2025 21:52:38 +0300 Subject: [PATCH 2/4] Add dfs_completed flag, change the check whether dfs is completed in __iter__ method --- src/Depth_first_search/depth_first_search_class.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Depth_first_search/depth_first_search_class.py b/src/Depth_first_search/depth_first_search_class.py index 084f122..5aa41a7 100644 --- a/src/Depth_first_search/depth_first_search_class.py +++ b/src/Depth_first_search/depth_first_search_class.py @@ -4,6 +4,7 @@ def __init__(self, vertices: list[int], edges:list[tuple[int, int]]) -> None: self.edges = edges self.visited_vertices = list() self.index = 0 + self.dfs_completed = False def dfs(self) -> list[int]: states = {"white": [v for v in self.vertices], @@ -26,11 +27,13 @@ def dfs_step(vertex): for vertex in self.vertices: if vertex in states["white"]: dfs_step(vertex) + self.dfs_completed = True return self.visited_vertices def __iter__(self): - if self.visited_vertices == []: + if not self.dfs_completed: self.visited_vertices = self.dfs() + self.dfs_completed = True self.index = 0 return self From d52c0cddca7f9c4d557d4c6bc6da3921248832a2 Mon Sep 17 00:00:00 2001 From: Yana Kalsina Date: Wed, 26 Nov 2025 22:13:01 +0300 Subject: [PATCH 3/4] Create tests for depth first search --- tests/test_for_depth_first_search.py | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 tests/test_for_depth_first_search.py diff --git a/tests/test_for_depth_first_search.py b/tests/test_for_depth_first_search.py new file mode 100644 index 0000000..70d8223 --- /dev/null +++ b/tests/test_for_depth_first_search.py @@ -0,0 +1,71 @@ +from src.Depth_first_search.depth_first_search_class import Graph + +def test_linear_graph(): + """ 1 - 2 - 3 """ + graph = Graph([1, 2, 3], [(1, 2), (2, 3)]) + dfs_result = graph.dfs() + assert len(dfs_result) == 3 + assert set(dfs_result) == {1, 2, 3} + iter_result = list(graph) + assert iter_result == dfs_result + + +def test_branched_graph(): + """ 1 + / \ + 2 3 + | + 4 + """ + graph = Graph([1, 2, 3, 4], [(1, 2), (1, 3), (2, 4)]) + dfs_result = graph.dfs() + assert len(dfs_result) == 4 + assert set(dfs_result) == {1, 2, 3, 4} + assert dfs_result[0] == 1 + +def test_disconnected_graph(): + """ 1-2 3-4 """ + graph = Graph([1, 2, 3, 4], [(1, 2), (3, 4)]) + dfs_result = graph.dfs() + assert len(dfs_result) == 4 + assert set(dfs_result) == {1, 2, 3, 4} + + +def test_single_vertex(): + graph = Graph([1], []) + dfs_result = graph.dfs() + assert dfs_result == [1] + assert list(graph) == [1] + +def test_empty_graph(): + graph = Graph([], []) + dfs_result = graph.dfs() + assert dfs_result == [] + assert list(graph) == [] + + +def test_multiple_iterations(): + graph = Graph([1, 2], [(1, 2)]) + first_iter = list(graph) + second_iter = list(graph) + assert first_iter == second_iter + assert len(first_iter) == 2 + + +def test_dfs_order(): + graph = Graph([1, 2, 3, 4], [(1, 2), (2, 3), (3, 4), (1, 4)]) + dfs_result = graph.dfs() + assert len(dfs_result) == 4 + assert dfs_result[0] == 1 + assert dfs_result == [1, 2, 3, 4] + + + +def test_complex_graph(): + graph = Graph([1, 2, 3, 4, 5], [(1, 2), (1, 3), (2, 4), (3, 5), (4, 5)]) + dfs_result = graph.dfs() + assert len(dfs_result) == 5 + assert set(dfs_result) == {1, 2, 3, 4, 5} + assert dfs_result[0] == 1 + + From b552048edd095d6f1fc3dafb59619808d2155385 Mon Sep 17 00:00:00 2001 From: Yana Kalsina Date: Sun, 7 Dec 2025 13:37:33 +0300 Subject: [PATCH 4/4] Fixed iter method so now it returns an iterator, add self.visited_vertices = [] in dfs function --- .../depth_first_search_class.py | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/Depth_first_search/depth_first_search_class.py b/src/Depth_first_search/depth_first_search_class.py index 5aa41a7..5cb120b 100644 --- a/src/Depth_first_search/depth_first_search_class.py +++ b/src/Depth_first_search/depth_first_search_class.py @@ -4,9 +4,9 @@ def __init__(self, vertices: list[int], edges:list[tuple[int, int]]) -> None: self.edges = edges self.visited_vertices = list() self.index = 0 - self.dfs_completed = False def dfs(self) -> list[int]: + self.visited_vertices = [] states = {"white": [v for v in self.vertices], "grey": list(), "black": list()} @@ -24,22 +24,30 @@ def dfs_step(vertex): dfs_step(edge[0]) states["black"].append(vertex) states["grey"].remove(vertex) + for vertex in self.vertices: if vertex in states["white"]: dfs_step(vertex) - self.dfs_completed = True return self.visited_vertices + def __iter__(self): - if not self.dfs_completed: - self.visited_vertices = self.dfs() - self.dfs_completed = True - self.index = 0 - return self - - def __next__(self): - if self.index >= len(self.visited_vertices): - raise StopIteration - vertex = self.visited_vertices[self.index] - self.index += 1 - return vertex \ No newline at end of file + class GraphIterator: + def __init__(self, visited_vertices): + self.visited_vertices = visited_vertices + self.index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.index >= len(self.visited_vertices): + raise StopIteration + vertex = self.visited_vertices[self.index] + self.index += 1 + return vertex + + if not self.visited_vertices: + self.visited_vertices = self.dfs() + + return GraphIterator(self.visited_vertices) \ No newline at end of file