簡體   English   中英

這個遞歸數組置換函數如何在引擎蓋下工作?

[英]How does this recursive array permutation function work under the hood?

此函數生成數組的排列。 我已經用紙筆在開發工具中添加了斷點,並且精心地逐步完成了每個函數調用,但我仍然不明白這是如何工作的。

具體來說,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]));

謝謝!

一般來說,我不是使用斷點來跟蹤這些,而是​​使用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,lenitem

對於您的具體問題,當前三個調用標識[1,2,3]作為解決方案時,狀態如下所示:

堆:

  1. doIt ,i = 0,len = 1,item = 3
  2. doIt ,i = 0,len = 2,item = 2
  3. 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),為temp選擇2 ,然后我們從以2開始的答案開始。

這足以讓你獲得這個想法嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM