"过多的递归"重复的变化

时间:2014-11-07 17:21:45

标签: javascript recursion combinatorics

我试图制作一个功能,列出所有可能的重复变化。 我做的那个回归"过多的递归"。

function variants(amount, chars, junk){
    var junkarray = junk.split(",");
    var newjunk;
    if(junkarray[junkarray.length-1]==amount){
        newjunk = ",";
    }
    if(junk.length==Math.pow(chars.length, amount)){
        console.log(junk);
        return;
    }else{
        for(var i = 0; i < chars.length; i++){
            variants(amount, chars, junk+newjunk+chars[i]);
        }
    }
}
variants(3, ["1", "2"],"");

2 个答案:

答案 0 :(得分:3)

您的问题是,您从未点击过退出子句,并且您正在获得无限递归。你的问题在于:

var newjunk;
...
variants(amount, chars, junk+newjunk+chars[i]);

您没有将newjunk初始化为任何内容,因此当它跳过有可能设置它的部分时,您的变量仍未定义。因此,当您将字符串连接到else子句中的其他变量时,发生的事情是js将值“undefined”转换为“undefined”字符串。对于测试cut-n-paste这一行:

var newjunk; var junk = ""; var chars = ["1","2"]; console.log(result, junk+newjunk+chars[0]); 

进入你最喜欢的控制台。请注意,它打印出undefined1。修复它的方法是将newjunk初始化为空字符串:

var newjunk = ""

以下是此更改的jsfiddle

调试递归问题的一个好方法是打破一张纸和笔,并在每行代码中进行物理跟踪,以确保您的exit子句被命中。您还可以以函数内部递增的全局计数变量的形式添加过早退出条件。当此计数变量达到特定值时,退出。

答案 1 :(得分:1)

虽然IngoBürk的答案确实解释了为什么你会遇到无限递归,但它解决了一个稍微不同的问题。这是一个似乎有用的解决方案( Fiddle ):

var variants = function(amount, chars, soFar) {
    soFar = soFar || [""];
    if (amount === 0) {return soFar;}
    var partials = soFar.map(function(partial) {
        return chars.map(function(char) {
            return partial.concat(char);
        });
    }).reduce(function(a, b) {return a.concat(b);}, []);
    return variants(amount - 1, chars, partials);
};

var v = variants(3, ["1", "2"]);
//=> ["111", "112", "121", "122", "211", "212", "221", "222"] 

请注意,这也会导致数据太大的递归问题,但对于相当小的数据集,您应该没问题。

更新

可能有点干净不会宣布第三个参数,它只能在内部用于递归调用,所以 this Fiddle 让它好一点,我想:< / p>

var variants = function(amount, chars) {
    var soFar = arguments[2] || [""];
    // ... no other changes.
}