Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,16 @@
* Singly Linked List
* [Node](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/node.py)
* [Single Linked List](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/single_linked_list.py)
* [Single Linked List Utils](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/single_linked_list_utils.py)
* [Test Singly Linked Delete](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_delete.py)
* [Test Singly Linked List](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list.py)
* [Test Singly Linked List Nth To Last](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_nth_to_last.py)
* [Test Singly Linked List Pairwise Swap](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_pairwise_swap.py)
* [Test Singly Linked List Remove Duplicates](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_duplicates.py)
* [Test Singly Linked List Remove Nth Last Node](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_nth_last_node.py)
* [Test Singly Linked List Reorder List](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_reorder_list.py)
* [Test Singly Linked List Rotate](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_rotate.py)
* [Test Singly Linked Merge And Weave](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_merge_and_weave.py)
* [Test Singly Linked Move Tail To Head](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_move_tail_to_head.py)
* [Test Singly Linked Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_palindrome.py)
* [Test Singly Linked Revese](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_revese.py)
Expand Down
33 changes: 33 additions & 0 deletions datastructures/linked_lists/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,3 +715,36 @@ def pairs_with_sum(self, target: T) -> List[Tuple[Node, Node]]:
List: list of pairs
"""
raise NotImplementedError("not yet implemented")

@staticmethod
def reverse_list(head: Node) -> Optional[Node]:
"""
Reverses a linked list given the head node
Args:
head Node: the head node of the linked list
Returns:
Optional[Node]: the new head node of the reversed linked list
"""
if head is None or head.next is None:
return head

# track previous node, so we can point our next pointer to it
previous = None
# track node to loop through
current_node = head

while current_node:
# track the next node to not lose it while adjusting pointers
nxt = current_node.next

# set the next pointer to the node behind it, previous
current_node.next = previous

# adjust the new previous node to the current node for subsequent loops
previous = current_node

# move our node pointer up to the next node in front of it
current_node = nxt

# return the new tail of the k-group which is our head
return previous
26 changes: 26 additions & 0 deletions datastructures/linked_lists/singly_linked_list/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,29 @@ Here `n` is the number of nodes in the linked list
- Stack

---

## Reorder List

Given the head of a singly linked list, reorder the list as if it were folded on itself. For example, if the list is
represented as follows:

L0 -> L1 -> L2 -> L3 -> L4 -> L5

The reordered list should be:

L0 -> L5 -> L1 -> L4 -> L2 -> L3

You don’t need to modify the values in the list’s nodes; only the links between nodes need to be changed.

### Constraints

- The range of number of nodes in the list is [1, 500]
- -5000 <= `node.value` <= 5000

### Examples

![Example 1](./images/examples/singly_linked_list_reorder_list_example_1.png)
![Example 2](./images/examples/singly_linked_list_reorder_list_example_2.png)
![Example 3](./images/examples/singly_linked_list_reorder_list_example_3.png)
![Example 4](./images/examples/singly_linked_list_reorder_list_example_4.png)
![Example 5](./images/examples/singly_linked_list_reorder_list_example_5.png)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
from datastructures.linked_lists.singly_linked_list.node import SingleNode
from datastructures.linked_lists import LinkedList, T, Node
from datastructures.linked_lists.exceptions import EmptyLinkedList
from datastructures.linked_lists.singly_linked_list.single_linked_list_utils import (
reverse_list,
merge_and_weave,
)


class SinglyLinkedList(LinkedList):
Expand Down Expand Up @@ -983,6 +987,36 @@ def reverse_list(head_node: SingleNode) -> SingleNode:
def remove_tail(self):
pass

def reorder_list(self) -> Optional[SingleNode]:
"""
Reorders the linked list in place.
Returns:
head node of reversed linked list
"""
# return early if there is no head node
if self.head is None:
return None

# first split the linked list into two halves. To do this without knowing the length of the linked list beforehand
# we must first find the middle node. This uses the slow & fast pointer approach
middle_node = self.middle_node()

# Store the second half head node
second_half_head = middle_node.next
# cut the connection between the first half and the second half
middle_node.next = None

# Now, we need to reverse the second half of the linked list in place
# The reversal step involves taking the second half of the linked list and reversing it in place
# for example, if the linked list is 1 -> 2 -> 3 -> 4 -> 5, the second half is 3 -> 4 -> 5
# after reversing, it becomes 5 -> 4 -> 3
reversed_second_half = self.reverse_list(second_half_head)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find the file location
FILE_PATH=$(find . -name "single_linked_list.py" -type f 2>/dev/null | head -1)

if [ -z "$FILE_PATH" ]; then
    echo "File not found. Searching for variations..."
    find . -name "*linked_list*.py" -type f 2>/dev/null | grep -i single | head -5
else
    echo "Found file: $FILE_PATH"
    
    # Check line 8 for imports
    echo "=== Lines around line 8 (imports) ==="
    sed -n '1,20p' "$FILE_PATH"
    
    # Check line 1013
    echo ""
    echo "=== Line 1013 (the problematic line) ==="
    sed -n '1010,1016p' "$FILE_PATH"
    
    # Check if reverse_list is defined as a method in the class
    echo ""
    echo "=== Searching for reverse_list definitions ==="
    grep -n "def reverse_list" "$FILE_PATH"
    
    # Check for self.reverse_list calls
    echo ""
    echo "=== Checking for self.reverse_list calls ==="
    grep -n "self\.reverse_list" "$FILE_PATH"
fi

Repository: BrianLusina/PythonSnips

Length of output: 1556


Fix incorrect method call on line 1013.

self.reverse_list(second_half_head) attempts to call reverse_list as a class method, but reverse_list is imported as a standalone function (line 8), not a method of SinglyLinkedList. This will cause an AttributeError at runtime.

-        reversed_second_half = self.reverse_list(second_half_head)
+        reversed_second_half = reverse_list(second_half_head)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reversed_second_half = self.reverse_list(second_half_head)
reversed_second_half = reverse_list(second_half_head)
🤖 Prompt for AI Agents
In datastructures/linked_lists/singly_linked_list/single_linked_list.py around
line 1013, the code calls self.reverse_list(second_half_head) but reverse_list
is imported as a standalone function (not a SinglyLinkedList method); replace
the method call with a call to the imported function
(reverse_list(second_half_head)) and ensure the top-level import for
reverse_list remains correct and used consistently in this file.


# now we can merge and weave the first half and the reversed second half
reordered_list = merge_and_weave(self.head, reversed_second_half)

return reordered_list

def kth_to_last_node(self, k: int) -> Optional[SingleNode]:
"""
Gets the Kth to the last node.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from typing import Optional
from datastructures.linked_lists.singly_linked_list.node import SingleNode


def merge_and_weave(
first_half_head: SingleNode, second_half_head: SingleNode
) -> Optional[SingleNode]:
"""
Merges and weaves the first half and the reversed second half of the linked list in place.
Args:
first_half_head: head node of the first half of the linked list
second_half_head: head node of the reversed second half of the linked list
Returns:
head node of the merged and weaved linked list
"""
if first_half_head is None or second_half_head is None:
return None
Comment on lines +16 to +17
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cd datastructures/linked_lists/singly_linked_list && find . -name "*.py" | head -20

Repository: BrianLusina/PythonSnips

Length of output: 611


🏁 Script executed:

cat -n datastructures/linked_lists/singly_linked_list/single_linked_list_utils.py | head -80

Repository: BrianLusina/PythonSnips

Length of output: 2483


🏁 Script executed:

# Also search for usage in single_linked_list.py
grep -n "merge_and_weave\|reorder" datastructures/linked_lists/singly_linked_list/single_linked_list.py | head -20

Repository: BrianLusina/PythonSnips

Length of output: 259


🏁 Script executed:

sed -n '985,1025p' datastructures/linked_lists/singly_linked_list/single_linked_list.py

Repository: BrianLusina/PythonSnips

Length of output: 1636


Fix early-return logic for edge cases in merge_and_weave.

The function returns None when either input is None. For single-node lists passed from reorder_list, this causes incorrect behavior—a single node should be returned unchanged, not None. Change lines 16-17 to return the non-None input:

if first_half_head is None:
    return second_half_head
if second_half_head is None:
    return first_half_head
🤖 Prompt for AI Agents
In datastructures/linked_lists/singly_linked_list/single_linked_list_utils.py
around lines 16 to 17, the early-return incorrectly returns None when one list
is missing; instead return the non-None head so single-node lists are preserved.
Replace the combined None-check with two checks: if first_half_head is None
return second_half_head; if second_half_head is None return first_half_head,
preserving the existing list when the other side is absent.


p1 = first_half_head
p2 = second_half_head

while p2:
# save the pointer 1 next node to not loose it
p1_next = p1.next
p2_next = p2.next

# now we can move the pointers
p1.next = p2
p2.next = p1_next

p1, p2 = p1_next, p2_next

return first_half_head


def reverse_list(head: SingleNode) -> Optional[SingleNode]:
"""
Reverses a linked list given the head node
Args:
head Node: the head node of the linked list
Returns:
Optional[Node]: the new head node of the reversed linked list
"""
if head is None or head.next is None:
return head

# track previous node, so we can point our next pointer to it
previous = None
# track node to loop through
current_node = head

while current_node:
# track the next node to not lose it while adjusting pointers
nxt = current_node.next

# set the next pointer to the node behind it, previous
current_node.next = previous

# adjust the new previous node to the current node for subsequent loops
previous = current_node

# move our node pointer up to the next node in front of it
current_node = nxt

# return the new tail of the k-group which is our head
return previous
Comment on lines +36 to +66
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Eliminate code duplication for reverse_list.

This reverse_list function duplicates the implementation in:

  • datastructures/linked_lists/__init__.py (lines 719-749)
  • datastructures/linked_lists/singly_linked_list/single_linked_list.py (lines 907-927, inline in reverse_groups)

Consider consolidating to a single canonical implementation (likely the static utility in __init__.py) and importing it where needed, rather than maintaining three identical copies.

Based on learnings, code duplication should be avoided to reduce maintenance burden and potential for divergence.

🤖 Prompt for AI Agents
datastructures/linked_lists/singly_linked_list/single_linked_list_utils.py lines
36-66: this reverse_list implementation is a duplicate; remove the local
function and instead import the canonical reverse_list from
datastructures.linked_lists (the static utility in __init__.py), update this
module to export or use that imported function, ensure Optional and SingleNode
types are imported/referenced consistently, and update any local calls to use
the imported function so there’s a single maintained implementation across the
codebase.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import unittest
from typing import List
from parameterized import parameterized
from datastructures.linked_lists.singly_linked_list.single_linked_list import (
SinglyLinkedList,
)

TEST_CASES = [
([1, 2, 3, 4, 5], [1, 5, 2, 4, 3]),
([1, 2, 3, 4], [1, 4, 2, 3]),
([1, 1, 2, 2, 3, -1, 10, 12], [1, 12, 1, 10, 2, -1, 2, 3]),
([10, 20, -22, 21, -12], [10, -12, 20, 21, -22]),
([1, 3, 5, 7, 9, 10, 8, 6, 4, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
([1, 2, 3, 4, 5, 6], [1, 6, 2, 5, 3, 4]),
(
[7, 0, 10, 13, 12, 19, 1, 3, 6, 7, 4, 2, 11],
[7, 11, 0, 2, 10, 4, 13, 7, 12, 6, 19, 3, 1],
),
([0, 8, 3, 1, 2, 7], [0, 7, 8, 2, 3, 1]),
([7, 4, 6, 1, 5, 8], [7, 8, 4, 5, 6, 1]),
([9, 0, 8, 2], [9, 2, 0, 8]),
([6, 8, 7], [6, 7, 8]),
]


class ReorderListTestCase(unittest.TestCase):
@parameterized.expand(TEST_CASES)
def test_reorder_list(self, input_list: List[int], expected_output: List[int]):
linked_list = SinglyLinkedList()
for data in input_list:
linked_list.append(data)

actual = linked_list.reorder_list()
self.assertIsNotNone(actual)

# since the head node is returned, we want the values of the linked list and not just the head node
# to check that the actual reordering worked
actual_list: List[int] = []
curr = actual
while curr:
actual_list.append(curr.data)
curr = curr.next

self.assertEqual(expected_output, actual_list)


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from typing import List
import unittest
from parameterized import parameterized
from datastructures.linked_lists.singly_linked_list.single_linked_list import (
SinglyLinkedList,
)
from datastructures.linked_lists.singly_linked_list.single_linked_list_utils import (
merge_and_weave,
)

TEST_CASES = [
([1, 2, 3], [6, 5, 4], [1, 6, 2, 5, 3, 4]),
([1, 2, 3], [4, 5], [1, 4, 2, 5, 3]),
]


class MergeAndWeaveSinglyLinkedListTestCase(unittest.TestCase):
def test_return_none_for_empty_linked_list(self):
"""should return none for an empty linked list when attempting to reverse"""
linked_list_one = SinglyLinkedList()
linked_list_two = SinglyLinkedList()

actual = merge_and_weave(linked_list_one.head, linked_list_two.head)
self.assertIsNone(actual)

@parameterized.expand(TEST_CASES)
def test_merge_and_weave(
self, list_one_data: List[int], list_two_data: List[int], expected: List[int]
):
linked_list_one = SinglyLinkedList()
# add the data to the linked list
for d in list_one_data:
linked_list_one.append(d)

linked_list_two = SinglyLinkedList()
# add the data to the linked list
for d in list_two_data:
linked_list_two.append(d)

actual = merge_and_weave(linked_list_one.head, linked_list_two.head)

actual_list: List[int] = []
curr = actual
while curr:
actual_list.append(curr.data)
curr = curr.next

# perform assertion
self.assertEqual(expected, actual_list)


if __name__ == "__main__":
unittest.main()
Loading
Loading