Skip to content

Commit 121bfda

Browse files
committed
Add Merge Sort Linked List algorithm
1 parent a9ca110 commit 121bfda

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
class Node:
2+
"""
3+
A class representing a node in a linked list.
4+
5+
Attributes:
6+
data (int): The data stored in the node.
7+
next (Node | None): A reference to the next node in the linked list.
8+
9+
>>> head = Node(4)
10+
>>> head.next = Node(2)
11+
>>> head.next.next = Node(1)
12+
>>> head.next.next.next = Node(3)
13+
>>> sorted_head = merge_sort_linked_list(head)
14+
>>> print_linked_list(sorted_head)
15+
1 2 3 4
16+
"""
17+
18+
def __init__(self, data: int):
19+
self.data = data
20+
self.next: Node | None = None
21+
22+
23+
def get_middle(head: Node) -> Node:
24+
"""
25+
Find the middle node of the linked list using the slow and fast pointer technique.
26+
27+
Parameters:
28+
head: The head node of the linked list.
29+
30+
Returns:
31+
The middle node of the linked list.
32+
33+
Example:
34+
>>> head = Node(1)
35+
>>> head.next = Node(2)
36+
>>> head.next.next = Node(3)
37+
>>> get_middle(head).data
38+
2
39+
"""
40+
41+
if head is None:
42+
return head
43+
44+
slow = head # one node at a time
45+
fast = head # two nodes at a time
46+
while fast.next and fast.next.next:
47+
slow = slow.next
48+
fast = fast.next.next
49+
return slow
50+
51+
52+
def merge(left: Node | None, right: Node | None) -> Node | None:
53+
"""
54+
Merge two sorted linked lists into one sorted linked list.
55+
56+
Parameters:
57+
left: The head of the first sorted linked list.
58+
right: The head of the second sorted linked list.
59+
60+
Returns:
61+
The head of the merged sorted linked list.
62+
63+
Example:
64+
>>> left = Node(1)
65+
>>> left.next = Node(3)
66+
>>> right = Node(2)
67+
>>> right.next = Node(4)
68+
>>> merged = merge(left, right)
69+
>>> print_linked_list(merged)
70+
1 2 3 4
71+
"""
72+
73+
if left is None:
74+
return right
75+
if right is None:
76+
return left
77+
78+
if left.data <= right.data:
79+
result = left
80+
result.next = merge(left.next, right)
81+
else:
82+
result = right
83+
result.next = merge(left, right.next)
84+
85+
return result
86+
87+
88+
def print_linked_list(head: Node | None) -> None:
89+
"""
90+
Print the linked list in a single line.
91+
92+
Parameters:
93+
head: The head node of the linked list.
94+
95+
Example:
96+
>>> head = Node(1)
97+
>>> head.next = Node(2)
98+
>>> head.next.next = Node(3)
99+
>>> print_linked_list(head)
100+
1 2 3
101+
"""
102+
103+
current = head
104+
first = True # To avoid printing space before the first element
105+
while current:
106+
if not first:
107+
print(" ", end="")
108+
print(current.data, end="")
109+
first = False
110+
current = current.next
111+
print()
112+
113+
114+
def merge_sort_linked_list(head: Node | None) -> Node | None:
115+
"""
116+
Sort a linked list using the Merge Sort algorithm.
117+
118+
Parameters:
119+
head: The head node of the linked list to be sorted.
120+
121+
Returns:
122+
The head node of the sorted linked list.
123+
124+
Example:
125+
>>> head = Node(4)
126+
>>> head.next = Node(2)
127+
>>> head.next.next = Node(1)
128+
>>> head.next.next.next = Node(3)
129+
>>> sorted_head = merge_sort_linked_list(head)
130+
>>> print_linked_list(sorted_head)
131+
1 2 3 4
132+
133+
>>> head = Node(1)
134+
>>> head.next = Node(2)
135+
>>> head.next.next = Node(3)
136+
>>> head.next.next.next = Node(4)
137+
>>> sorted_head = merge_sort_linked_list(head)
138+
>>> print_linked_list(sorted_head)
139+
1 2 3 4
140+
141+
>>> head = Node(10)
142+
>>> head.next = Node(3)
143+
>>> head.next.next = Node(5)
144+
>>> head.next.next.next = Node(1)
145+
>>> sorted_head = merge_sort_linked_list(head)
146+
>>> print_linked_list(sorted_head)
147+
1 3 5 10
148+
"""
149+
150+
# Base Case: 0 or 1 node
151+
if head is None or head.next is None:
152+
return head
153+
154+
# Split the linked list into two halves
155+
middle = get_middle(head)
156+
next_to_middle = middle.next
157+
middle.next = None # Split the list into two parts
158+
159+
left = merge_sort_linked_list(head) # Sort the left half
160+
right = merge_sort_linked_list(next_to_middle) # Sort the right half
161+
sorted_list = merge(left, right) # Merge the sorted halves
162+
return sorted_list
163+
164+
165+
if __name__ == "__main__":
166+
import doctest
167+
168+
doctest.testmod()

0 commit comments

Comments
 (0)