JavaScript中如何反转链表?

来源:微信开发网作者:印尼程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《JavaScript中如何反转链表?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《JavaScript中如何反转链表?》有用,将其分享出去将是对创作者最好的鼓励。

在JavaScript中处理链表相关问题时,反转链表是最基础也最常见的操作之一,掌握它的实现逻辑对理解数据结构的操作方式很有帮助。链表是由多个节点组成的数据结构,每个节点包含自身的值和指向下一个节点的指针,反转链表就是要把所有节点的指针方向调转,让原本的尾节点变成头节点,原本的头节点变成尾节点。

JavaScript中如何反转链表?

链表的基础结构定义

在JavaScript中,我们通常通过构造函数或者类来定义链表节点,每个节点有两个属性,一个是存储当前节点的值,另一个是指向下一个节点的引用。首先我们先定义链表节点的结构:

// 定义链表节点类
class ListNode {
  constructor(val, next = null) {
    this.val = val; // 节点存储的值
    this.next = next; // 指向下一个节点的指针,默认是null
  }
}

我们可以通过以下方式创建一个简单的链表:1 -> 2 -> 3 -> 4 -> null,代码如下:

// 创建链表 1->2->3->4->null
const node1 = new ListNode(1);
const node2 = new ListNode(2);
const node3 = new ListNode(3);
const node4 = new ListNode(4);
node1.next = node2;
node2.next = node3;
node3.next = node4;

迭代法反转链表

迭代法是反转链表最常用的实现方式,核心思路是通过三个指针依次遍历链表,逐步调整每个节点的指针方向。三个指针的作用分别是:

  • prev:指向当前节点的前一个节点,初始值为null,因为反转后原来的头节点会变成尾节点,尾节点的next是null
  • curr:指向当前正在处理的节点,初始值是链表的头节点
  • next:指向当前节点的下一个节点,用来保存遍历时的后续节点,避免调整指针后丢失后续链表

迭代的具体步骤是:先保存当前节点的下一个节点,然后把当前节点的next指向prev,接着把prev移动到当前节点,当前节点移动到之前保存的下一个节点,重复这个过程直到当前节点为null,此时prev就是反转后的链表头节点。

迭代法的完整实现代码如下:

function reverseListIterative(head) {
  let prev = null; // 前一个节点初始为null
  let curr = head; // 当前节点从头部开始
  while (curr !== null) {
    const next = curr.next; // 保存下一个节点
    curr.next = prev; // 反转当前节点的指针
    prev = curr; // prev移动到当前节点
    curr = next; // 当前节点移动到下一个节点
  }
  return prev; // 循环结束后prev就是新的头节点
}

我们可以测试一下迭代法的效果:

const reversedHead = reverseListIterative(node1);
// 遍历反转后的链表,输出结果应该是4 3 2 1
let temp = reversedHead;
while (temp !== null) {
  console.log(temp.val);
  temp = temp.next;
}

递归法反转链表

除了迭代法,我们还可以用递归的方式实现链表反转,递归的核心思路是先递归到链表的最后一个节点,然后从后往前逐步调整指针方向。递归的终止条件是当前节点为null或者当前节点的next为null,此时当前节点就是原链表的尾节点,也就是反转后的头节点。

递归的实现逻辑是:假设我们已经反转了当前节点之后的所有节点,那么只需要把当前节点的下一个节点的next指向当前节点,然后把当前节点的next设为null,就可以完成整个链表的反转。

递归法的完整实现代码如下:

function reverseListRecursive(head) {
  // 终止条件:链表为空或者只有一个节点,直接返回
  if (head === null || head.next === null) {
    return head;
  }
  // 递归反转后面的链表,得到反转后的头节点
  const newHead = reverseListRecursive(head.next);
  // 把当前节点的下一个节点的next指向当前节点,实现指针反转
  head.next.next = head;
  // 当前节点的next设为null,避免形成环
  head.next = null;
  return newHead;
}

同样测试递归法的效果:

// 重新创建原链表,因为之前的链表已经被反转过了
const n1 = new ListNode(1);
const n2 = new ListNode(2);
const n3 = new ListNode(3);
const n4 = new ListNode(4);
n1.next = n2;
n2.next = n3;
n3.next = n4;

const reversedHead2 = reverseListRecursive(n1);
let temp2 = reversedHead2;
while (temp2 !== null) {
  console.log(temp2.val);
  temp2 = temp2.next;
}

两种方法的对比

迭代法和递归法都可以实现链表反转,两者各有特点:

方法时间复杂度空间复杂度特点
迭代法O(n),n是链表长度,需要遍历一次链表O(1),只使用了固定的几个指针变量逻辑直观,效率更高,没有递归调用栈的开销
递归法O(n),需要递归调用n次O(n),递归调用栈的深度是链表长度代码更简洁,但是链表过长时可能出现栈溢出问题

在实际开发中,如果链表长度不确定或者较长,优先选择迭代法实现反转链表,避免递归带来的栈溢出风险。如果是处理较短的链表,并且希望代码更简洁,递归法也是不错的选择。

JavaScript反转链表链表数据结构修改时间:2026-07-09 13:45:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。