Skip to content

Conversation

@BrianLusina
Copy link
Owner

@BrianLusina BrianLusina commented Jan 22, 2026

Describe your change:

Detect and remove cycles

  • 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 linked-list cycle utilities: detection, cycle-length calculation, cycle-entry detection, cycle removal, and removal of the nth node from the end.
  • Breaking Changes

    • The cycle-removal operation now returns a value instead of modifying the list in-place.

✏️ Tip: You can customize this high-level summary in your review settings.

@BrianLusina BrianLusina self-assigned this Jan 22, 2026
@BrianLusina BrianLusina added enhancement Algorithm Algorithm Problem Datastructures Datastructures Documentation Documentation Updates Two Pointers Two pointer algorithm LinkedList Linked List Data Structure Utilities labels Jan 22, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

Cycle-detection and manipulation logic was moved from LinkedList methods into new standalone utilities in linked_list_utils. LinkedList methods now delegate to these utilities. remove_cycle on LinkedList changed signature to return Optional[Node] and now returns the utility result.

Changes

Cohort / File(s) Summary
Cycle Detection Utilities
datastructures/linked_lists/linked_list_utils.py
Added public utilities: has_cycle(head, func=None), cycle_length(head), detect_node_with_cycle(head), remove_cycle(head), and remove_nth_from_end(head, n). Extended imports to include Callable and Any.
LinkedList Method Refactoring
datastructures/linked_lists/__init__.py
Replaced in-method cycle logic with calls to the new utilities (has_cycle, cycle_length, detect_node_with_cycle, remove_cycle). Updated remove_cycle(self) -> Optional[Node] signature and imports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🐰 I hopped through nodes both near and far,
I chased my tail, found the cycle's star.
I pulled it out with a careful twitch,
Now lists run straight — hop, hop, no glitch! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description is mostly complete with the required template sections and nearly all checklist items completed. However, a discrepancy exists: the commit message indicates an additional feature (remove_nth_from_end) not mentioned in the PR description. Clarify whether remove_nth_from_end is part of this PR scope. If included, update the PR description's 'Describe your change' section to mention this addition alongside cycle detection/removal utilities.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding utilities to detect and remove cycles in linked lists, which aligns with the primary objectives of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

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: 5

🤖 Fix all issues with AI agents
In `@datastructures/linked_lists/linked_list_utils.py`:
- Around line 44-50: The cycle-detection block uses slow_pointer, fast_pointer
and an optional func but when a cycle is found and func is provided the function
calls func(...) then falls through to return False, contradicting the docstring;
update the code in that branch so after calling func(slow_pointer, fast_pointer)
the function returns True (i.e., ensure both the func and non-func paths return
True when slow_pointer is fast_pointer) so the function consistently reports a
detected cycle.
- Around line 71-77: The cycle-detection loop mixes identity and equality
comparisons: the initial check uses "is" (slow_pointer is fast_pointer) but the
loop uses "!=" which invokes Node.__eq__ (compares keys) and can mis-detect
cycles when distinct nodes have equal keys; update the loop condition to use
identity ("is not") so both comparisons use identity semantics (referencing
slow_pointer and fast_pointer in the function containing the loop) to correctly
count the cycle length.
- Line 132: Change the node comparison in the loop to use identity comparison:
in the while loop that currently checks "while current.next != fixed_pointer"
(variables current and fixed_pointer), replace the inequality operator with an
identity check so it reads as "while current.next is not fixed_pointer"; this
ensures consistent node identity comparison with other functions that use "is" /
"is not".
- Line 39: The tuple unpacking "fast_pointer, slow_pointer = head" is invalid
because head is a single Node; replace it by assigning both pointers to the head
node (set fast_pointer and slow_pointer to head) so both start at the list head;
update the initialization in linked_list_utils.py where fast_pointer,
slow_pointer and head are referenced to use individual assignments (e.g., set
fast_pointer = head and slow_pointer = head) so subsequent logic in functions
using fast_pointer and slow_pointer works correctly.
- Around line 99-105: Replace equality checks with identity checks in the
cycle-detection logic: where the code compares slow_pointer and fast_pointer
(currently using ==) and where it compares current and slow_pointer (currently
using !=), use "is" and "is not" respectively so comparisons use object identity
rather than Node.__eq__ (which compares keys); update the comparisons in the
function containing slow_pointer, fast_pointer, current and head to use "is" /
"is not" so distinct nodes with equal keys are not treated as the same node.
🧹 Nitpick comments (2)
datastructures/linked_lists/linked_list_utils.py (1)

27-27: Unnecessary f-string prefix on docstring.

The docstring uses f""" but contains no interpolated expressions. Use a regular docstring instead.

♻️ Proposed fix
-    f"""
+    """
datastructures/linked_lists/__init__.py (1)

412-415: Guard clause is redundant with utility function behavior.

The check on lines 412-413 is unnecessary because remove_cycle in the utility already handles these cases via detect_node_with_cycle returning None and then returning head. Consider removing for consistency with other delegating methods.

♻️ Proposed simplification
     def remove_cycle(self) -> Optional[Node]:
         """
         Removes cycle if there exists. This will use the same concept as has_cycle method to check if there is a loop
         and remove the cycle
         Returns:
             Node: head node with cycle removed
         """
-        if not self.head or not self.head.next:
-            return self.head
-
         return remove_cycle(self.head)

@BrianLusina BrianLusina merged commit b0cd89c into main Jan 22, 2026
6 of 8 checks passed
@BrianLusina BrianLusina deleted the feat/data-structures-linked-list-remove-cycle branch January 22, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Algorithm Algorithm Problem Datastructures Datastructures Documentation Documentation Updates enhancement LinkedList Linked List Data Structure Two Pointers Two pointer algorithm Utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants