此函数生成数组的排列。我已经用纸笔在开发工具中添加了断点,并且精心地逐步完成了每个函数调用,但我仍然不明白这是如何工作的。
具体来说,for循环。一旦do It函数拼接出数组中的所有数字,它就会将临时数组的切片副本推送到应答数组中。然后它将item拼接到参数数组中,从temp数组中弹出相同的项,并返回for循环的第一次迭代的答案。因此,在循环数组一次后,答案= [1,2,3] temp = [1,2]和arr = [3]。
这是我迷路的地方。它似乎跳回到接头并拼接2回到arr。在devTools中,我把手表放在i,item,temp和arr上。它说我在某种程度上变成了1,即使在我们将3拼接回来之后,arr中只有一个项目。如果长度为1且for循环指定它应该停止在arr.length运行,它如何以某种方式跳回到拼接2回到数组?
如果我的语法不连贯,我很抱歉。我今天花了很多时间来讨论这件事。
TDLR。运行此功能。在do it函数的for循环中放置一个断点。一旦数组为空并且我们返回答案,它如何将两个项目拼接回原始的arr。
function permute(arr) {
var temp = [];
var answer = [];
function logResult() {
answer.push(
// make a copy of temp using .slice()
// so we can continue to work with temp
temp.slice()
);
}
function doIt() {
var i;
var len;
var item;
for (i = 0, len = arr.length; i < len; i++) {
// remove the item at index i
item = arr.splice(i, 1)[0];
// add that item to the array we're building up
temp.push(item);
if (arr.length) {
// if there's still anything left in the array,
// recurse over what's left
doIt();
} else {
// otherwise, log the result and move on
logResult();
}
// restore the item we removed at index i
// and remove it from our temp array
arr.splice(i, 0, item);
temp.pop();
}
return answer;
}
return doIt();
};
console.log(permute([1,2,3]));
谢谢你!
答案 0 :(得分:4)
一般情况下,我不是使用断点来跟踪这些,而是使用print语句。 当我输入函数时,我打印函数名称和参数值。当我离开时,我打印名称并退出(返回和状态)值。在这种情况下,我在循环中做同样的事情。现在,让我们看看更像英语的伪代码
依次为每个数组元素: 从 arr 中删除该元素,并将其附加到项 如果我们已经清空了 arr 将项记录为下一个排列 其他 在 arr 中重复使用少一个元素,在项
中重复一次// When we reach this point, we've exhausted all the permutations that
// begin with the original state of **item**.
// Back up one element
take the chosen element from **item** and re-append it to **arr**.
// Go to the next loop iteration, which will move to the next element.
当您解决这个问题时,请记住您在运行时堆栈上多次调用 doIt :第一个遍历项[0]的所有3个可能选项;第二个遍历项[1]的2个可能选项,第三个选择剩余元素,记录排列,然后备份到第二个调用。每个呼叫实例都保持其本地值 i,len,和项。
对于您的具体问题,当前三个调用标识[1,2,3]作为解决方案时,状态如下所示:
堆栈:
doIt ,i = 0,len = 3,item = 1
我们现在回到上一个呼叫,#2,从堆栈弹出#3呼叫。 在此次通话中,我们刚从#3 doIt 电话回来。我们跳转到 restore 点,将2拼接回 arr ,然后迭代到循环的顶部。
将 i 增加到1,从 arr 中选择值3,留下temp = [1,3]和arr = 2。重复 doIt ,另一个电话#3 ...
...选择剩余的 2 ,记录解决方案[1,3,2],将 2 放回 arr ,并返回呼叫#2。
将#2拼接 3 重新调回 arr ,迭代,将 i 增加到2,现在已经耗尽其 for < / strong>循环。它将 1 拼接回 arr 并返回调用#1。
我们现在有temp = [],arr = [1,2,3],只有我们原来的 doIt 调用堆栈。它前进到下一个循环迭代(i = 1),选择 2 temp ,我们从 2 开头的答案开始。
这足以让你获得这个想法吗?