## Question:

I went through my merge_sort function and it seems okay. It updates the curr1 and curr2 inside the loop but I am not sure why I get into the infinite loop.

def merge_sorted(root1,root2):
"""Ascending Order"""

if root1 == None:
return root2

if root2 == None:
return root1

curr1 = root1
curr2 = root2
new_root = None
new_tail = None

# init r and t
if curr1.val > curr2.val:
new_root = curr2
new_tail = curr2
else: # curr1.val <= curr2.val
new_root = curr1
new_tail = curr1

# merge
while curr1 and curr2:
if curr1.val > curr2.val:
# curr2 goes first
new_tail.nxt = curr2
new_tail = new_tail.nxt
curr2 = curr2.nxt
else: # curr1.val <= curr2.val
# curr1 goes first
new_tail.nxt = curr1
new_tail = new_tail.nxt
curr1 = curr1.nxt

if curr1:
new_tail.nxt = curr1

if curr2:
new_tail.nxt = curr2

return new_root

In future, please post complete code, enough for people to run to reproduce your problem. In this case, we’re missing the class wrapping .val and .nxt, and have no clue about what the inputs may have been when you got your infinite loop.

In any case, this looks shallow, getting off track near the start: after your very first compare, you need to advance whichever of curr1 and curr2 was the winner. Suppose, e.g., that curr1.val won. Then you need to do curr1 = curr1.nxt so you don’t compare it again. But the code doesn’t. So curr1 wins the second (identical!) compare too, and, in effect, curr1.nxt = curr1 is done. That’s where the infinite loop comes from: the linked list has been turned into an endless cycle.

## Alternative

"The problem" with a linked list merge is that you want to plant a link to the winner in the "next" field of the current tail. But, at the start there is no "current" tail. So, as you did, we typically see a special case made out of the very first compare. Which opens the door to problems unique to that special case.

An alternative is to create an artificial node at the start, and call it "the current tail". Then there are no special cases, and at the end just return the value of that artificial node’s "next" link:

def merge_sorted(root1, root2):
if root1 is None:
return root2

if root2 is None:
return root1

while True:
if root1.val > root2.val:
# 2 goes first
winner.nxt = root2
winner = root2
root2 = root2.nxt
if root2 is None:
winner.nxt = root1
break
else:
# 1 goes first
winner.nxt = root1
winner = root1
root1 = root1.nxt
if root1 is None:
winner.nxt = root2
break

When you append a node to become the new tail of the merged list, you should move the corresponding curr reference one step ahead. You do this in the loop, but forgot doing this in the initial case (before the loop).

So change this:

if curr1.val > curr2.val:
new_root = curr2
new_tail = curr2
else:
new_root = curr1
new_tail = curr1

to this:

if curr1.val > curr2.val:
new_root = curr2
new_tail = curr2
curr2 = curr2.nxt  # <---
else:
new_root = curr1
new_tail = curr1
curr1 = curr1.nxt  # <---

## Why the infinite loop?

Without this correction, you’ll create a loop in the list. Let’s assume that curr1.val > curr2.val at the very start, then new_tail will be made to reference the same node as curr2 (the if case).

Then in the loop, this condition will still be true: curr1.val > curr2.val and then in the if block we set new_tail.nxt = curr2. But as new_tail was the same as curr2, we actually do curr2.nxt = curr2. This introduces a cycle in the linked list. The next statement new_tail = new_tail.nxt will follow that cycle so that new_tail doesn’t actually change, and the same fate befalls curr2 which also doesn’t advance with curr2 = curr2.nxt… and so things go very wrong from that point onwards: nothing changes, and the next iteration of the loop will get into the same if block with the same nodes referenced by new_tail and curr2 and these references fail to get anywhere else.

It is crucial that at the start of every iteration of the loop, new_tail is not equal to curr1 nor to curr2. new_tail is intended to reference the last node in the merged part of the list, while curr1 and curr2 are intended to reference the first nodes of the non-merged parts of the original lists.

Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.