Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions dfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from collections import defaultdict

# This class represents a directed graph using
# adjacency list representation
class Graph:
Comment on lines +3 to +5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to Python's style guide PEP 257, it's standard practice to use docstrings ("""...""") for documenting classes, functions, and modules. This is more idiomatic than using a comment block above the class definition and allows tools to automatically generate documentation and users to get help via the help() function.

    """Represents a directed graph using an adjacency list."""


# Constructor
def __init__(self):

# Default dictionary to store graph
self.graph = defaultdict(list)


# Function to add an edge to graph
def addEdge(self, u, v):
self.graph[u].append(v)
Comment on lines +15 to +16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Per Python's style guide PEP 8, method names should be in snake_case. Additionally, PEP 257 recommends using docstrings for documenting functions instead of comments above them.

    def add_edge(self, u, v):
        """Adds an edge from vertex u to v."""



# A function used by DFS
def DFSUtil(self, v, visited):

# Mark the current node as visited
# and print it
visited.add(v)
print(v, end=' ')

# Recur for all the vertices
# adjacent to this vertex
for neighbour in self.graph[v]:
if neighbour not in visited:
self.DFSUtil(neighbour, visited)
Comment on lines +20 to +31

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This method can be significantly improved in terms of reusability and Python conventions:

  1. Reusability: Printing directly to the console couples the traversal logic with a specific action. A more flexible design is to make this a generator that yields each node. The caller can then decide what to do with the nodes (e.g., print them, collect them into a list).
  2. Naming (PEP 8): Helper methods intended for internal use should be prefixed with an underscore (e.g., _dfs_util) and use snake_case.
  3. Documentation (PEP 257): The comment should be converted to a docstring.
    def _dfs_util(self, v, visited):
        """A recursive generator for DFS traversal from a given vertex."""
        visited.add(v)
        yield v

        # Recur for all the vertices adjacent to this vertex
        for neighbour in self.graph[v]:
            if neighbour not in visited:
                yield from self._dfs_util(neighbour, visited)



# The function to do DFS traversal. It uses
# recursive DFSUtil()
def DFS(self, v):

# Create a set to store visited vertices
visited = set()

# Call the recursive helper function
# to print DFS traversal
self.DFSUtil(v, visited)
Comment on lines +36 to +43

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This DFS implementation has two main issues:

  1. Correctness/Clarity: It only traverses the graph from a specific starting vertex v. If the graph has multiple disconnected components, it will only visit the component containing v. The method name DFS is misleading as it implies a full graph traversal. Renaming it to dfs_from_vertex makes its behavior explicit and the API clearer.
  2. API Design: To work with the suggested generator-based _dfs_util, this method should return the generator to the caller.
    def dfs_from_vertex(self, v):
        """Performs DFS traversal starting from a given vertex.

        Returns:
            A generator that yields nodes in DFS order.
        """
        # Create a set to store visited vertices for this traversal
        visited = set()

        # Return the generator from the helper function
        return self._dfs_util(v, visited)



# Driver's code
if __name__ == "__main__":
g = Graph()
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)

print("Following is Depth First Traversal (starting from vertex 2)")

# Function call
g.DFS(2)
Comment on lines +47 to +59

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This driver code needs to be updated to reflect the suggested changes to method names (add_edge, dfs_from_vertex) and to correctly handle the generator returned by the new DFS implementation.

if __name__ == "__main__":
    g = Graph()
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 2)
    g.add_edge(2, 0)
    g.add_edge(2, 3)
    g.add_edge(3, 3)

    print("Following is Depth First Traversal (starting from vertex 2)")

    # The dfs_from_vertex method returns a generator.
    # We can unpack it with * to print all items.
    traversal_generator = g.dfs_from_vertex(2)
    print(*traversal_generator)