When I tried to reverse the Linked list, I noticed that the results varied depending on how I did the assignments.
Why does it happen as bellow?
class ListNode:
def __init__(self, val=0, next: Optional["ListNode"] = None):
self.val = val
self.next = next
# It works as expected with unpacking assignment.
nodes = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
rev = None
while nodes is not None:
rev, rev.next, nodes = nodes, rev, nodes.next
# rev = [5, 4, 3, 2, 1]
# But dose not work as expected when assigning one by one.
cnt = 0
nodes = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
rev = None
while nodes is not None:
if cnt > 10:
break
rev = nodes
rev.next = rev
nodes = nodes.next
cnt = 1
# rev = [1, 1, 1, 1, 1...] Infinite loop in circular reference!
My Environments:
- Python 3.10.7
Thanks a lots.
CodePudding user response:
What applies here is
rev, rev.next, nodes = nodes, rev, nodes.next
the right-hand expression is evaluated before the left-hand assignement. So you assign nodes.next to nodes and rev to rev.next. That's why it is correct.
In the second loop. You killing the link here
rev.next = rev
after this it can not stop
CodePudding user response:
The first example is a tuple assignment. They all happen at the same time.
In the second example the assignments happen one after the other and rev.next
points to itself which causes the self-reference loop.
Consider the below example:
class F: pass
a = F()
b = F()
c = F()
a.name = 'a'
b.name = 'b'
c.name = 'c'
a.name, b.name, c.name = c.name, b.name, a.name
print(a.name)
print(b.name)
print(c.name)
outputs
c
b
a
but
class F: pass
a = F()
b = F()
c = F()
a.name = 'a'
b.name = 'b'
c.name = 'c'
a.name = c.name
b.name = b.name
c.name = a.name
print(a.name)
print(b.name)
print(c.name)
outputs
c
b
c
This is due to the fact that by the time c.name = a.name
is executed, a.name
is already 'c'
and not 'a'
.