javascript-此递归数组置换函数如何在后台运行?

此函数生成数组的排列.我已经花了很多笔钱,并在开发工具中设置了断点,并辛苦地逐步完成了每个函数的调用,但是我仍然不了解这是如何工作的.

具体来说,是for循环.一旦do It函数将数组中的所有数字拼接起来,就会将temp数组的切片副本推入答案数组.然后,它将项目拼接到参数数组中,从temp数组中弹出相同的项目,并返回for循环的第一次迭代的答案.因此,在循环遍历一次数组后,答案= [1,2,3],温度= [1,2],arr = [3].

这是我迷路的地方.似乎跳回了接头,接头2又回到了arr.在devTools中,我监视了i,item,temp和arr.它说即使我们将3拼接回去之后,即使在arr中只有一项,我仍然以某种方式变为1.如果长度为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]));

谢谢!

解决方法:

通常,我不使用断点而是使用打印语句来跟踪它们.
输入函数时,我将打印函数名称和参数值.离开时,我将打印名称并退出(返回和状态)值.在这种情况下,我将在循环内执行相同的操作.现在,让我们用更像英语的伪代码来看看

对于每个数组元素依次:
    从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调用:第一个遍历item [0]的所有3种可能选择;第二个遍历item [1]的2个可能选择,第三个遍历其余元素,记录排列,然后备份到第二个调用.每个调用实例都维护其本地值i,len和item.

对于您的特定问题,当前三个调用将[1、2、3]标识为解决方案时,状态如下:

堆:

> doIt,i = 0,len = 1,item = 3
> doIt,i = 0,len = 2,item = 2
> doIt,i = 0,len = 3,item = 1

> arr = [3],temp = [1,2]

现在我们返回到上一个调用#2,将调用#3从堆栈中弹出.
在此调用中,我们刚刚从#3 doIt调用返回.我们跳到还原点,将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,现在n已耗尽其for循环.它将1拼接回arr并返回到调用#1.

现在,我们有temp = [],arr = [1、2、3],并且只有我们原来的doIt调用在堆栈上.前进到下一个循环迭代(i = 1),为2选择2
临时,我们从以2开头的答案开始.

足够的追踪让您理解吗?

上一篇:的Permute字符串,直到它匹配一些输入?


下一篇:MySQL快速检查哈希是否存在