这可能有助于想象您给出的示例会发生什么。重要的是要意识到这个递归函数的每个执行上下文都有自己的一组局部变量。尽管不同的执行上下文的变量名称相同,但它们是不同的。
在主调用中我们有:
head
↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │ │ val: 4 │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘ └─────────┘ └─────────┘ └─────────┘
↑ ↑
first_node second_node
然后递归调用发生,它有自己的变量(名称相同,但它们不同):
head
↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │ │ val: 4 │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘ └─────────┘ └─────────┘ └─────────┘
↑ ↑
first_node second_node
这里有一个更深层次的递归调用,它又有自己的head变量None
head
↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │ │ val: 4 │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘ └─────────┘ └─────────┘ └─────────┘
...它从第一个 if 块返回 None。
剩余的递归调用取回这个None返回值并将其分配给first_node.next:
head
↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │ │ val: 4 │
│ next: ───> │ next: ───> │ next: ───┐ │ next: ───> None
└─────────┘ └─────────┘ └─────────┘│ └─────────┘ ^
↑ └───────────────┘
first_node ↑
second_node
然后second_node.next = first_node被执行:
head ┌──────────────┐
↓ V │
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐│
│ val: 1 │ │ val: 2 │ │ val: 3 │ │ val: 4 ││
│ next: ───> │ next: ───> │ next: ───┐ │ next: ───┘ None
└─────────┘ └─────────┘ └─────────┘│ └─────────┘ ^
↑ └─────────────────┘
first_node ↑
second_node
让我们重新排序最后两个节点的可视化,而不更改任何引用:
head
↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 │ │ val: 2 │ │ val: 4 │ │ val: 3 │
│ next: ───> │ next: ───┐ │ next: ───> │ next: ───> None
└─────────┘ └─────────┘│ └─────────┘ └─────────┘
│ ^
└────────────────┘
↑ ↑
second_node first_node
然后second_node 从递归调用中返回,所以我们回到第一个执行上下文(带有它自己的局部变量),其中first_node.next 被分配了返回值:
head ┌────────────────┐
↓ │ V
┌─────────┐│ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 ││ │ val: 2 │ │ val: 4 │ │ val: 3 │
│ next: ───┘ │ next: ───┐ │ next: ───> │ next: ───> None
└─────────┘ └─────────┘│ └─────────┘ └─────────┘
│ ^
└────────────────┘
↑ ↑ ↑
first_node second_node returned
然后second_node.next = first_node被执行:
head ┌────────────────┐
↓ │ V
┌─────────┐│ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 1 ││ │ val: 2 │ │ val: 4 │ │ val: 3 │
│ next: ───┘ │ next: ───┐ │ next: ───> │ next: ───> None
└─────────┘ └─────────┘│ └─────────┘ └─────────┘
^ │
└────────────────┘
↑ ↑
first_node second_node
让我们在不更改引用的情况下再次重新排序可视化:
head
↓
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ val: 2 │ │ val: 1 │ │ val: 4 │ │ val: 3 │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘ └─────────┘ └─────────┘ └─────────┘
↑ ↑
second_node first_node
最后,second_node 作为新的头部返回。