生成字符串

时间:2015-10-02 04:33:04

标签: javascript string

//====================================================
function getPermutations(str){
    //Enclosed data to be used by the internal recursive function permutate():
    var permutations = [],  //generated permutations stored here
        nextWord = [],      //next word builds up in here     
        chars = []          //collection for each recursion level
    ;
    //---------------------
    //split words or numbers into an array of characters
    if (typeof str === 'string') chars = str.split(''); 
    else if (typeof str === 'number') {
      str = str + ""; //convert number to string
      chars = str.split('');//convert string into char array
    }
    //============TWO Declaratives========
    permutate(chars);
    return permutations;
    //===========UNDER THE HOOD===========
    function permutate(chars){ //recursive: generates the permutations
        if(chars.length === 0)permutations.push(nextWord.join(''));            
        for (var i=0; i < chars.length; i++){
            chars.push(chars.shift());  //rotate the characters
            nextWord.push(chars[0]);    //use the first char in the array            
            permutate(chars.slice(1));  //Recurse: array-less-one-char
            nextWord.pop();             //clear for nextWord (multiple pops)
        }
    }
    //--------------------------------
}//==============END of getPermutations(str)=============

nextWord.pop()多次被调用? 不会置换(chars.slice(1));不要让nextWord.pop()执行,因为它会带你回到permutate函数的顶部?

此外,当chars变为空时,调用它上的切片permutate(chars.slice(1));谁再次填充角色?字符是否由nextWord.pop()填充;因为pop将值返回到permutate函数?

在chrome调试器中单步执行此代码并不清楚。

5 个答案:

答案 0 :(得分:1)

enter image description here递归调用permutate在循环内部,每次执行时都将它放在调用堆栈中。多次调用nextWord.pop以完成执行堆栈上的每个递归调用。您可以使用此工具http://visualgo.net/recursion.html可视化递归。如果你有一个像Webstorm这样的工具,你可以在调试器中运行它,看看在第一次调用nextWord.pop时堆栈中有三个permutate()调用。

答案 1 :(得分:0)

它将在premutate()返回后执行。但我想通过查看代码就可以看出这一点。我想你的问题是如何预先进行复活?答案是查看for循环。

因为我们每次只用一个字符来调用premutate()。有意义的是,在某个时刻我们对premutate()的一个调用将被调用一个空数组:

premutate([]); // happens when chars.slice(1) gives us an empty array

现在,让我们看看发生这种情况时会发生什么:

function permutate(chars){

    // The following gets executed:
    if(chars.length === 0)permutations.push(nextWord.join(''));

    // This for loop is skipped because 0 < 0 is false
    for (var i=0; i < chars.length; i++){/*...*/}

    // we return because we skipped the for loop
}

现在基本案例已经返回,对premutate()的所有其他调用也会返回:

function permutate(chars){
    if(chars.length === 0)permutations.push(nextWord.join(''));
    for (var i=0; i < chars.length; i++){
        chars.push(chars.shift());
        nextWord.push(chars[0]);
        permutate(chars.slice(1));  // This have returned..
        nextWord.pop();             // so execute this line
    }

    // and return so that other calls to us can also execute pop()
}

答案 2 :(得分:0)

chars.slice(1)是从位置1开始的字符数组chars,即第二个字符,因此调用permutate(chars.slice(1));以少1个字符进行递归。

最终,chars.slice(1)将返回零个字符,此时permutations.push(nextWord.join(''));将被执行,for (var i=0; i < chars.length; i++)将不执行内部循环块,因为其终止条件i < chars.length已经存在如果i的初始值为0chars.length也为零,则为false。

因此,这个递归函数的终止条件是当前单词中的字符用完时。

permutate函数最终返回时,每次调用nextWord.pop()时都会调用permutate一次。

答案 3 :(得分:0)

调用permutate不会将您置于排列顶部。 (正如joe所提到的)它只是等待这个子调用完成然后继续执行该方法。

我认为你的递归排列可以简化:

// suppose input = "abc"
permutate(chars) {
  if(chars.length === 2) return [chars, chars[0] + chars[1]};
  var arr = permutate(chars.slice(1)) // returns ["bc", "cb"]
  var out = []    
  for (var i=0; i < arr.length; i++) {
    for (var j = 0; j < chars.length - 1; ++j) {
      out.push(arr[i].split(0,j) + chars[0] +  arr[i].split(j)) // "a" gets inserted at every possible position in each string
    }
  }
  // result here is ["abc", "bac", "bca", "acb", "cab", "cba"]
  return out
}

答案 4 :(得分:0)

function permutate(left, used, result) { 
    // If there are no more characters left to permute 
    if (0 == left.length) { 
       result.push(used); 
    } 

    // Iterate over all characters in the 'left' string
    for (var i = 0; i < left.length; ++i) { 
       // Read the character we are going to work with in this iteration 
       var iObject = left[i]; 

       // Create a new_left string that contains all the characters 
       // of the 'left' string without the one we are going to use now 
       var new_left = ''; 
       for (j = 0; j < left.length; ++j) { 
          if (j != so.i) new_left += so.left[j]; 
       } 

       // Create a new_used string that has all the characters of 'used'  
       // plus the one we are going to use now 
       var new_used = so.used + iObject; 

       // Call permute with new_left and new_used strings 
       permutate(new_left, new_used, result); 
    } 
} 

要在某些字符串上运行该函数,您需要像这样调用它:

permutate('abcd', '', []);

对于因涉及递归而无法获得此功能的人,我找到了一个页面,用于说明使用交互式动画的算法流程。

http://learntocode.guru/code/generate-permutations-recursively-string

只需点击播放并观察变量变化,而置换功能一直在调用自身。还要观察何时找到新的排列以及何时将其添加到生成的排列数组中。