[英]How does this recursive function to reverse a linked list work?
I found the function below that reverses a linked list recursively:我在下面找到了递归反转链表的 function:
def recursive(self, head, end):
if not head:
return None, None
if head.next == end:
head.next = None
return head, head
newHead, newEnd = self.recursive(head.next, end)
newEnd.next = head
head.next = None
return newHead, head
I understand the if
statements that cover for the base case.我理解涵盖基本情况的if
语句。
But I do not understand the recurrence relation.但我不明白递归关系。
How does that recursion work to reverse the list?该递归如何反转列表? Is there a more simple recursive version that reverses a linked list?是否有更简单的递归版本来反转链表? For reference, I am solving LeetCode problem 206. Reverse Linked List :作为参考,我正在解决 LeetCode 问题206。反向链表:
Given the
head
of a singly linked list, reverse the list, and return the reversed list .给定单链表的head
,反转该列表,并返回反转后的列表。
I do not understand the recurrence relation.我不明白递归关系。
Let's say we have this linked list:假设我们有这个链表:
head end
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 85 │ │ value: 15 │ │ value: 20 │
│ next: ———————→ │ next: ———————→ ...more nodes...——→ │ next:null │
└───────────┘ └───────────┘ └───────────┘
The recursive part is based on the following observation:递归部分基于以下观察:
If you can reverse a list that is one element shorter, which excludes the current head
node, then we should arrive in a situation like this:如果您可以反转一个元素较短的列表,其中不包括当前的head
节点,那么我们应该会遇到这样的情况:
head end
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 85 │ │ value: 15 │ │ value: 20 │
│ next: ———————→ │ │ │ │
│ │ │ next:null │ ←——...more nodes...←———————— :next │
└───────────┘ └───────────┘ └───────────┘
↑ ↑
newEnd newHead
At this stage we do not question how it did that.在这个阶段,我们不会质疑它是如何做到的。 We just assume it works for the recursive case.我们只是假设它适用于递归情况。 So if it works correctly, we should get the above state of the list.所以如果它工作正常,我们应该得到上面的 state 列表。
Now the remaining statements will link the current head
node so that it finishes the reversal job for a list that includes this node also:现在剩下的语句将链接当前的head
节点,以便它完成包含该节点的列表的反转作业:
newEnd.next = head
This produces this state:这产生了这个 state:
head end
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 85 │ │ value: 15 │ │ value: 20 │
│ next: ———————→ │ │ │ │
│ │ ←——————— :next │ ←——...more nodes...←———————— :next │
└───────────┘ └───────────┘ └───────────┘
↑ ↑
newEnd newHead
Then we execute:然后我们执行:
head.next = None
These two assignments have made the current head
a tail node to the reversed list we got back from recursion:这两个分配使当前head
成为我们从递归返回的反向列表的尾节点:
head end
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 85 │ │ value: 15 │ │ value: 20 │
│ next:null │ ←——————— :next │ ←——...more nodes...←———————— :next │
└───────────┘ └───────────┘ └───────────┘
↑ ↑
newEnd newHead
Now we just need to tell the caller which is the head and tail node of this reversed list:现在我们只需要告诉调用者哪个是这个反向列表的头和尾节点:
return newHead, head
When you look at the final state, you see indeed that those are the head and tail of the reversed list.当您查看最终的 state 时,您确实会看到这些是反向列表的头部和尾部。
So, now, we know that:所以,现在,我们知道:
By induction you can then see that if it works for a list with just one node, it also works for a list with 2, with 3, ...etc.通过归纳,您可以看到如果它适用于只有一个节点的列表,它也适用于具有 2、3、...等的列表。
end
references, so you should not need to use them.您链接到的 LeetCode 问题不使用end
引用,因此您不需要使用它们。 An iterative method is to keep a reference of the preceding node while you walk along the list and relink each next
reference.一种迭代方法是在您沿着列表遍历并重新链接每个next
引用时保留前一个节点的引用。 Here is how that works for the LeetCode challenge (no end
reference):以下是 LeetCode 挑战的工作原理(无end
参考):
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
prev = None
while head:
head.next, prev, head = prev, head, head.next
return prev
Actually, I don't understand that function.实际上,我不明白function。 First, you should only need to be passing to such a function the head of the list;首先,您应该只需要将这样一个 function 传递给列表的头部; I don't know why argument end is being passed or why it even needs to be passed.我不知道为什么要传递参数end或者为什么甚至需要传递它。 Also, argument self suggests that this is a method that is part of a class definition that is not being shown.此外,自变量表明这是一种方法,它是未显示的 class 定义的一部分。 Let's start anew:让我们重新开始:
Here is a simple class for defining a node that can be linked to another node and be tagged with a "name" for identification.这是一个简单的 class 用于定义一个节点,该节点可以链接到另一个节点并用“名称”标记以进行识别。 We also include a small function to walk the linked list to print out the nodes:我们还包括一个小的 function 来遍历链表以打印出节点:
class Node:
def __init__(self, name):
self.name = name
self.next = None
a = Node('A')
b = Node('B')
c = Node('C')
d = Node('D')
e = Node('E')
a.next = b
b.next = c
c.next = d
d.next = e
def print_list(head):
while head:
print(head.name)
head = head.next
print_list(a)
Prints:印刷:
A
B
C
D
E
Next we present the recursive function to reverse such a list.接下来我们提出递归 function 来反转这样的列表。 This function is passed the head node of the list, asserted to be not None
.这个 function 被传递给列表的头节点,断言不是None
。 The rest I have tried to explain as comments at each step of the algorithm. rest 我试图在算法的每个步骤中将其解释为注释。 A key point is comment 7: make what we had been pointing to now point back to us .一个关键点是评论 7:让我们现在指向的东西指向我们。 This relates to comment 5: we now point backwards to None in that when we set head.next = None
it will only stay None
if this node was the head node of the entire list.这与注释 5 相关:我们现在向后指向 None ,因为当我们设置head.next = None
时,它只会在该节点是整个列表的头节点时保持None
。 Otherwise, per comment 7, it will later on be updated to point back to a previous node.否则,根据评论 7,它将稍后更新以指向前一个节点。
def reverse(head):
assert(head) # 1. make sure head is not None
next_head = head.next # 2. get the next node, if any
if next_head is None: # 3. if we do not point to a next node, then
return head # 4. just return this node as the new head
head.next = None # 5. we now point backwards to None
# 6. otherwise, reverse recursively what we were pointing to and get the new head
new_head = reverse(next_head)
# 7. make what we had been pointing to now point back to us:
next_head.next = head
# 8. and return the new head
return new_head
# without comments for clarity:
def reverse_no_comments(head):
assert(head)
next_head = head.next
if next_head is None:
return head
head.next = None
new_head = reverse(next_head)
next_head.next = head
return new_head
def print_list(head):
while head:
print(head.name)
head = head.next
print('Reversed:')
new_head = reverse(a)
print_list(new_head)
Prints:印刷:
Reversed:
E
D
C
B
A
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.