提问人:GNG 提问时间:12/8/2021 最后编辑:trincotGNG 更新时间:12/9/2021 访问量:33
为什么我的链表代码在模块化可重用的 JavaScript 函数中不起作用?
Why does my linked list code not work in a modular reusable JavaScript function?
问:
为什么当我使代码更加模块化时,我的链表解决方案会失败?
我正在以链表格式处理 Leetcode “添加 2 个数字”的问题 2。
这是个问题:
你会得到两个非空的链表,代表两个非负整数。这些数字以相反的顺序存储,并且它们的每个节点都包含一个数字。将两个数字相加,然后以链表形式返回总和。
您可以假设这两个数字不包含任何前导零,除了数字 0 本身。
我有一个带有重复代码的工作解决方案。 当我将最后两个函数的主体抽象为可重用的函数时,我的解决方案失败了。为什么会这样?
我所做的一个假设是链表节点是对象,因此应该通过引用传递。至少在 JavaScript 中是这样。
这是我成功的解决方案(在使代码更加模块化之前)......
var addTwoNumbers = function(l1, l2) {
let l3 = new ListNode(0, null);
let head = l3;
let carry = 0;
while (l1 != null && l2 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l1.val + l2.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l1 = l1.next;
l2 = l2.next;
}
while (l1 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l1.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l1 = l1.next;
}
while (l2 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l2.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l2 = l2.next;
}
if (carry == 1) {
l3.next = new ListNode(carry, null);
}
return head.next;
};
这是我失败的解决方案......
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
let l3 = new ListNode(0, null);
let head = l3;
let carry = 0;
while (l1 != null && l2 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l1.val + l2.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l1 = l1.next;
l2 = l2.next;
}
while (l1 != null) {
carry = addRemainingNodes(l1, l3, carry);
}
while (l2 != null) {
carry = addRemainingNodes(l2, l3, carry);
}
if (carry == 1) {
l3.next = new ListNode(carry, null);
}
return head.next;
};
function addRemainingNodes(la, lb, carry) {
lb.next = new ListNode(carry, null);
lb = lb.next;
let sum = la.val + lb.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
lb.val = ones;
la = la.next;
return carry;
}
答:
我所做的一个假设是链表节点是对象,因此应该通过引用传递。
的确,它们是对象。变量可以具有对这些对象的引用。这不是将参数传递给函数时发生的特定情况。例如,是一个参考。正是这个引用通过值传递给函数,局部变量将其作为自己的值接收(对象引用被复制)。当该函数赋值给 时,这只会影响该局部变量...而不是用于将此值传递给函数的变量。l3
lb
lb
根据经验:当 JavaScript 函数为其参数变量之一赋值时,这只会对该局部变量1 产生影响。
但是,当函数改变参数变量的属性时,这将影响作为参数传递的对象。
总而言之,没有像 C++ 中那样的引用传递。JavaScript 使用按值传递机制,考虑到对象的值实际上是一个参考。
避免代码重用
就您而言,治疗应该像您对待的那样。就像函数返回被重新分配一样,它也应该返回.您可以通过返回具有这两个值的数组来做到这一点。然后,您可以在调用端使用解构分配。老实说,这看起来并不那么优雅,但有一种不同的方法可以避免代码重复:l3
carry
carry
l3
考虑到第二个和第三个循环永远不会进行迭代。这是因为在第一个循环完成后,最多只能有一个 和 是非。while
l1
l2
null
因此,对 和 之间的这种差异进行抽象,并仅使用一个循环来替换这两个循环:l1
l2
let lrest = l1 || l2; // This will select the non-null list if there is one
while (lrest != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = lrest.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
lrest = lrest.next;
}
1此规则存在罕见的例外情况。有一些别名行为,例如参数
在非严格模式下的工作方式。
评论