Skip to content

feat(datastructures, graphs): clone graph#170

Merged
BrianLusina merged 4 commits intomainfrom
feat/datastructures-graphs-clone-graph
Feb 6, 2026
Merged

feat(datastructures, graphs): clone graph#170
BrianLusina merged 4 commits intomainfrom
feat/datastructures-graphs-clone-graph

Conversation

@BrianLusina
Copy link
Owner

@BrianLusina BrianLusina commented Feb 6, 2026

Describe your change:

Clone graph algorithm

  • Add an algorithm?
  • Fix a bug or typo in an existing algorithm?
  • Documentation change?

Checklist:

  • I have read CONTRIBUTING.md.
  • This pull request is all my own work -- I have not plagiarized.
  • I know that pull requests will not be merged if they fail the automated tests.
  • This PR only changes one algorithm file. To ease review, please open separate PRs for separate algorithms.
  • All new Python files are placed inside an existing directory.
  • All filenames are in all lowercase characters with no spaces or dashes.
  • All functions and variable names follow Python naming conventions.
  • All function parameters and return values are annotated with Python type hints.
  • All functions have doctests that pass the automated testing.
  • All new algorithms have a URL in its comments that points to Wikipedia or other similar explanation.
  • If this pull request resolves one or more open issues then the commit message contains Fixes: #{$ISSUE_NO}.

Summary by CodeRabbit

  • New Features

    • Added a utility to deep-clone undirected graphs, preserving shared structure and connectivity and handling empty graphs.
  • Documentation

    • Added comprehensive README with problem description, examples and diagrams, explanation of the cloning approach, and complexity analysis (O(n+m) time, O(n) space).

@BrianLusina BrianLusina self-assigned this Feb 6, 2026
@BrianLusina BrianLusina added enhancement Algorithm Algorithm Problem Documentation Documentation Updates Graph Graph data structures and algorithms Depth First Search labels Feb 6, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a new "Clone Graph" entry and README under datastructures/graphs/undirected, plus a Node class and a clone(root: Optional[Node]) -> Optional[Node] implementation that deep-copies an undirected graph using DFS with a map of original→clone.

Changes

Cohort / File(s) Summary
Directory / Index
DIRECTORY.md
Adds hierarchical directory entry: Graphs > Edge > Undirected > Clone Graph > Node.
Documentation
datastructures/graphs/undirected/clone_graph/README.md
New comprehensive README describing problem statement, node structure, adjacency interpretation, constraints, examples, DFS solution with memoization (hash map), complexity notes, and diagrams.
Data Model
datastructures/graphs/undirected/clone_graph/node.py
Adds Node class with data: Any and neighbors: List["Node"], constructor initializes these attributes.
Algorithm Implementation
datastructures/graphs/undirected/clone_graph/__init__.py
Adds clone(root: Optional[Node]) -> Optional[Node] implementing recursive DFS cloning with an internal clone_helper and a dictionary mapping originals to clones; handles None input.

Sequence Diagram

sequenceDiagram
    participant Client
    participant CloneFn as clone()
    participant Helper as clone_helper()
    participant Map as nodes_cloned (dict)
    participant NewNode as Node (constructor)

    Client->>CloneFn: clone(root)
    CloneFn->>Map: initialize {}
    CloneFn->>Helper: clone_helper(root, Map)

    Helper->>Map: if node in Map?
    alt not in Map
        Helper->>NewNode: new Node(node.data)
        NewNode-->>Helper: cloned_node
        Helper->>Map: Map[node] = cloned_node
        loop for each neighbor
            Helper->>Map: is neighbor in Map?
            alt not in Map
                Helper->>Helper: recursive clone_helper(neighbor, Map)
                Helper-->>Helper: cloned_neighbor
            else
                Map-->>Helper: cloned_neighbor
            end
            Helper->>cloned_node: append cloned_neighbor to neighbors
        end
    else
        Map-->>Helper: return Map[node]
    end

    Helper-->>CloneFn: cloned_root
    CloneFn-->>Client: return cloned_root
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐇 I hop through nodes with cheerful delight,
I copy each neighbor, left and right,
With memoized map I never repeat,
A twin forest grows beneath my feet,
Hooray—an undirected clone, stitched neat! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a clone graph algorithm to the datastructures/graphs module.
Description check ✅ Passed The description follows the template structure and addresses all required sections with appropriate checklist items marked, though the change description is minimal.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/datastructures-graphs-clone-graph

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@datastructures/graphs/undirected/clone_graph/__init__.py`:
- Around line 21-24: The check for whether a neighbour has been cloned uses a
truthiness test "if not cloned_neighbour" which is fragile; change it to an
explicit None check "if cloned_neighbour is None" when using
nodes_cloned.get(neighbour) inside clone_helper so that cloned_neighbour is only
treated as missing when truly None; update the condition around
cloned_node.neighbors += [clone_helper(neighbour, nodes_cloned)] to use "is
None" with the cloned_neighbour variable (and keep the existing logic that calls
clone_helper and appends the result).
- Around line 5-6: The signature types are misleading because clone accepts None
and clone_helper checks for None; update the type hints to reflect that by
changing the parameter types from Node to Optional[Node] for both clone(root:
Node) and the helper clone_helper(n: Node, nodes_cloned: Dict[Node, Node]), and
adjust any related variable annotations (e.g., nodes_cloned values/keys if
needed) so static type checkers accept None inputs for Node; keep the runtime
logic unchanged.

In `@datastructures/graphs/undirected/clone_graph/README.md`:
- Around line 52-60: Remove the blank line between the Example 2 and Example 3
blockquotes to fix MD028 and make formatting consistent; additionally, match
Example 3 to the other examples by either adding a preceding heading like "###
Example 3" or inserting the same image tag pattern used in Examples 1–2, and
include the missing example image/visual for the empty graph case (the block
referencing "adjList = []") so Example 3 follows the same structure as "Example
2" (which shows "adjList = [[]]") and the other examples in the README.
🧹 Nitpick comments (4)
DIRECTORY.md (1)

444-446: DIRECTORY.md entry only lists Node, missing the clone algorithm itself.

The new entry links only to node.py. Consider also listing the clone graph module (__init__.py) and/or the README.md so the directory index reflects the full feature addition. If this file is auto-generated, disregard.

datastructures/graphs/undirected/clone_graph/node.py (1)

4-7: Consider a more descriptive parameter name and a __repr__ for debuggability.

The constructor parameter d is cryptic — renaming to data improves readability. A __repr__ method would simplify debugging and test output.

♻️ Suggested improvement
 class Node:
-    def __init__(self, d: Any):
-        self.data: Any = d
+    def __init__(self, data: Any):
+        self.data: Any = data
         self.neighbors: List["Node"] = []
+
+    def __repr__(self) -> str:
+        return f"Node(data={self.data})"
datastructures/graphs/undirected/clone_graph/__init__.py (2)

32-34: Inconsistent variable naming: nodes_completed vs nodes_cloned.

The outer function creates nodes_completed but the helper parameter is named nodes_cloned. Pick one name for consistency.

Proposed fix
-    nodes_completed: Dict[Node, Node] = {}
-    return clone_helper(root, nodes_completed)
+    nodes_cloned: Dict[Node, Node] = {}
+    return clone_helper(root, nodes_cloned)

24-28: Prefer .append() over += [x] for adding single items.

+= [x] creates an intermediate list on each iteration. .append(x) is more idiomatic and avoids the allocation.

Proposed fix
-                cloned_node.neighbors += [clone_helper(neighbour, nodes_cloned)]
+                cloned_node.neighbors.append(clone_helper(neighbour, nodes_cloned))
             else:
-                cloned_node.neighbors += [cloned_neighbour]
+                cloned_node.neighbors.append(cloned_neighbour)

BrianLusina and others added 2 commits February 6, 2026 21:26
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@BrianLusina BrianLusina merged commit 69df8e4 into main Feb 6, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Algorithm Algorithm Problem Depth First Search Documentation Documentation Updates enhancement Graph Graph data structures and algorithms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant