如何在仅能访问当前节点及其后继节点的前提下反转单链表

本文讲解如何仅通过调整指针引用(不借助额外数据结构如数组或栈)原地反转单链表,核心是使用三个指针(prev、curr、next)

迭代翻转相邻节点间的指向关系。

在给定的 LinkedList 实现中,first 是唯一对外暴露的入口,每个 Node 仅持有 elem 和指向下一节点的 next 引用——这意味着无法随机访问、无法回溯、不能新建节点或使用辅助容器。因此,反转必须严格通过重新链接 next 指针完成,即:将原链表 A → B → C → D → null 转为 D → C → B → A → null,同时将 first 更新为新的头节点(原尾节点)。

正确解法采用三指针迭代法,空间复杂度 O(1),时间复杂度 O(n):

  • prev:记录已反转部分的新头节点(初始为 null);
  • curr:当前待处理节点(初始为 first);
  • next:暂存 curr.next,防止在修改 curr.next 后丢失后续链路。

关键逻辑在于:对每个 curr,先保存其后继 next = curr.next,再将其 next 指向 prev(完成一次翻转),接着整体前移:prev = curr,curr = next,直至 curr == null。此时 prev 即为新链表头节点,赋值给 first 即可。

以下是完整、健壮的 reverse() 实现:

public void reverse() {
    Node prev = null;
    Node curr = first;

    while (curr != null) {
        Node next = curr.next; // 保存下一个节点,避免断链
        curr.next = prev;         // 反转当前节点的指针
        prev = curr;              // prev 前移到当前节点
        curr = next;              // curr 前移到原下一个节点
    }

    first = prev; // 更新头节点为原链表尾节点
}

⚠️ 注意事项:

  • 初始 prev = null 至关重要——它使原头节点翻转后自然指向 null,成为新尾节点;
  • 若链表为空(first == null)或仅一个节点,循环不执行,first = prev(即 null 或原节点)仍保持正确;
  • 切勿在循环内修改 elem 值(如提问中尝试的 first.elem = aux.elem),这属于“浅层复制”,未改变链式结构,且会破坏原始数据语义;
  • 该算法不依赖泛型 T 的具体类型,完全基于引用操作,符合题目“不可创建辅助数据结构”的约束。

总结:链表反转的本质是指针方向的批量重定向,而非元素搬运。掌握 prev–curr–next 三指针协作模式,是解决各类链表就地操作(如检测环、找中点、合并、分组反转)的基础范式。