用 JavaScript 实现链表操作 - 18 Recursive Reverse

TL;DR

用递归的方式反转链表,系列目录见 前言和目录

需求

实现函数 reverse() 用递归的方式反转链表。例子如下:

var list = 2 -> 1 -> 3 -> 6 -> 5 -> null
reverse(list) === 5 -> 6 -> 3 -> 1 -> 2 -> null

解法

让我们先思考一下递归的大概解法:

function reverse(head) {
  const node = new Node(head.data)
  const rest = reverse(head.next)
  // 把 node 放到 rest 的末尾,并返回 rest
}

麻烦的地方就在最后,把节点加入链表的末尾需要首先遍历整个链表,这无疑非常低效。我们在上一个 kata 的循环里是怎么解决的呢?维护一个 result 变量代表反转链表,然后每次把新节点放到 result 的头部,同时把新节点当做新的 result ,大概这个样子:

let result
for (let node = list; node; node = node.next) {
  result = new Node(node.data, result)
}

为了在递归里达到同样的效果,我们也必须维护这么一个变量。为了在每次递归过程中都能用到这个变量,我们得把它当函数的参数传递下去,reverse 的函数签名就变成这样:

function reverse(head, acc) { ... }

这里 acc 就是反转的链表。整理一番后的代码如下:

function reverse(head, acc = null) {
  return head ? reverse(head.next, new Node(head.data, acc)) : acc
}

上面这段代码同时也是尾递归。在递归函数中开额外的参数很是常见的做法,也是尾递归优化的必要手段。

参考资料

Codewars Kata
GitHub 的代码实现
GitHub 的测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值