我会试一试。
概述
您从两个具有全局范围的数组开始:permArray 最终将保存所有排列数组,usedChars 是一个工作数组,用于通过所有递归调用构建每个单独的排列数组。重要的是要注意,这是唯一两个在创建的每个函数的范围内都可以访问的变量。所有其他变量都对它们自己的函数调用具有局部作用域。
然后是递归函数,它接受一个数组作为输入,并返回一个数组数组,其中包含输入数组的所有可能排列。现在,在这个特定的函数中,递归调用在一个循环中。这很有趣,因为终止条件实际上比您的基本递归函数更复杂——当您传入一个空的 input 数组并且 for 循环跳过下一个递归调用时,递归调用终止。
总结
考虑一个四元素数组输入。在高层次上,该函数将遍历这个数组的四个元素,取出每个元素,并计算那个较小的三个元素数组的排列。通过所有这三个元素排列,它会将拉出的原始元素附加到开头,并将这四个元素数组中的每一个添加到permArray。
但是,为了找到较小的三元素数组的排列,我们取出每个元素,计算两个元素的较小数组的排列,将取出的元素添加到每个排列的开头,然后返回这三个元素数组中的每一个都在递归调用堆栈中向上,因此可以将原始的第四个元素添加到开头并计为一个排列。
但是,为了找到较小的两个元素数组的排列,我们取出每个元素,计算一个元素的较小数组的排列,将取出的元素添加到每个排列的开头,然后返回这两个元素数组中的每一个都在递归调用堆栈中向上,因此可以将原始的第三个元素添加到该排列的开头并返回堆栈。
但是,为了找到较小的一个元素数组的排列,我们取出元素并计算那个空数组的排列,它刚刚返回,然后我们又将我们的一个元素返回到堆栈中,所以原始的第二个元素可以添加到该排列的开头并返回堆栈。
详情
让我们注意这个函数中的一些步骤:
var permArr = [],
usedChars = [];
function permute(input) {
var i, ch;
for (i = 0; i < input.length; i++) { // loop over all elements
ch = input.splice(i, 1)[0]; //1. pull out each element in turn
usedChars.push(ch); // push this element
if (input.length == 0) { //2. if input is empty, we pushed every element
permArr.push(usedChars.slice()); // so add it as a permutation
}
permute(input); //3. compute the permutation of the smaller array
input.splice(i, 0, ch); //4. add the original element to the beginning
// making input the same size as when we started
// but in a different order
usedChars.pop(); //5. remove the element we pushed
}
return permArr //return, but this only matters in the last call
};
让我们使用数组 [4,3,2,1] 来追溯细节。
当它第一次传入时,我们将取出 4,将其推送到 usedChars,将其从输入中删除,然后在 [3,2,1] 上调用 permute。在此调用中,我们将 3 推送到 usedChars,将其从 input 中删除,然后在 [2,1] 上调用 permute。然后我们将 2 推送到 usedChars,将其从 input, and callpermuteon [1]. Then we push 1 tousedChars, and remove it frominput` 中删除。
这给我们留下了四个深度调用,在步骤 (2) 中:
ch=1
输入=[]
usedChars=[4,3,2,1]
在第 (2) 步,我们将把第一个排列 [4,3,2,1] 推送到 permArr。然后,继续前进,因为 input 现在为空,所以 (3) 中的递归调用将简单地返回,并且在 (4) 中,我们将简单地将 1 添加回输入并从 usedChars 中删除 1--然后此调用返回。
所以,此时,我们已经开始备份我们的递归调用,并坐在步骤 (4) 中:
ch=2
输入=[1]
usedChars=[4,3,2]
步骤(4)将执行算法的关键步骤:移动动作。它采用ch=2 并将其添加到input 的开头 并从usedChars 中删除它。这意味着在步骤(5)之后,我们有:
ch=2
输入=[2,1]
usedChars=[4,3]
现在看看我们在哪里。我们将 [4,3,2,1] 作为排列推送,然后备份并交换 2 和 1,现在我们将返回递归调用来构建 [4,3, 1,2] 并将其添加为排列。之后,我们将退出更多,移动更多元素,然后返回排列并添加它们。
回到它,在执行步骤 (5) 之后,我们循环。这意味着我们会将 1 推送到 usedChars 并使用 input=[2] 进行递归调用。该调用会将 2 推入 usedChars,创建一个完整的数组 [4,3,1,2] 并将其添加到 permArray。
因此,您将在递归调用中上下循环,建立一个排列,退出,重建一个不同的排列,然后退出,直到您循环了所有可能的组合。
我希望这会有所帮助!