代码问题

  1. Python链表指针指向下一位采取node=node.next,不要使用++
  2. 创建新链表记得初始化新链表
  3. 在链表操作之前,不要忘记检查Node的定义
  4. 遍历直接用for循环,无需计数器+while循环
  5. 在Python中,通过 self = self.next 修改自身引用是无效的。
  6. 在Python中,初始化一个空列表,通过.append(val)增加元素

困惑

1. 为什么 self = self.next 修改自身引用无效?

在 Python 中,self是方法的第一个参数,代表当前实例本身(比如链表对象)。但self本质上是一个局部变量—— 它只是 “指向实例的一个标签”。

当你在方法中写self = self.next时,你只是把这个 “标签” 从 “指向原来的实例” 改成了 “指向实例的 next 节点”,但原实例本身的结构并没有改变。

举个通俗的例子:
你手里拿着一串珠子(链表实例),self就像你 “握珠子的手”。当你说self = self.next,相当于你的手从 “握着第一个珠子” 移到了 “握着第二个珠子”,但这串珠子本身的连接方式(哪个珠子连哪个)并没有变化。外部看这串珠子,还是原来的样子。

2. 为什么 dummy 节点能达到预期效果?

dummy 节点(虚拟头节点)的核心作用是:提供一个 “固定不变的锚点”,让所有操作都通过修改这个锚点的 “连接关系” 来实现,而不是移动 “握锚点的手”。

3. 不使用 dummy 节点可以实现一样效果吗?

不使用 dummy 节点完全可以实现链表功能,核心是识别出头节点的特殊性并单独处理。当操作头节点时(如添加 / 删除),直接修改self.head的指向;而操作其他节点时,通过前驱节点的next指针进行修改。

4. 2种实现对比:

实现方式 优点 缺点
使用 dummy 节点 所有节点操作逻辑统一(无需特殊处理头节点) 多占用一个节点的内存空间
不使用 dummy 节点 节省一个节点的内存空间 需要单独处理头节点,操作逻辑稍显繁琐
实现更贴近链表原始定义(无额外虚拟节点) 边界情况(如空链表、单节点链表)需额外判断

5. 为什么对链表操作结束后返回的是None?

覆盖原链表后,返回的指针指向错误。
代码通过 head.val = _ 覆盖原链表的值,同时 head = head.next 移动指针。
当循环结束后,head 已经指向原链表的末尾(None 或最后一个节点的下一个位置),导致最终返回的是 None 而非新链表的头节点。

6. 如果要对链表进行遍历,最后需要返回整个链表,该怎么做?

先保存头指针
result_head = head
最后返回头指针
return result_head

7. 如何交换链表的2个节点?

代码示例
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: Optional[ListNode]
        :rtype: Optional[ListNode]
        """
        # 创建虚拟头节点,指向原链表头
        dummy = ListNode(0)
        dummy.next = head
        # prev 指向当前要交换的两个节点的前一个节点
        prev = dummy
        
        # 当存在至少两个节点可交换时
        while prev.next and prev.next.next:
            a = prev.next      # 第一个节点(要交换的左节点)
            b = prev.next.next # 第二个节点(要交换的右节点)
            next_group = b.next # 下一组节点的起始位置
            
            # 交换逻辑:prev -> b -> a -> next_group
            prev.next = b      # 前序节点连接到b(当前组新头)
            a.next = next_group # a连接到下一组,避免链表断裂
            b.next = a         # b连接到a,完成交换
            
            # 更新prev为当前组的尾节点a,准备处理下一组
            prev = a
        
        # 虚拟头节点的next即为交换后的新头
        return dummy.next

PLUS

  1. 虚拟头节点常用于需要增加or删除某些特定节点的场景,注意最后返回的是vir.next
  2. 由于链表每个节点都是同样的数据结构,同一场景下也进行同样处理,故可以考虑递归
  3. 可以直接使用等号tmp=head复制链表,对tmp进行操作而不改变原链表head
  4. 灵活地使用指针,单链表也能利用双链表的思想