if语句javascript中的递归函数中断

时间:2014-01-12 18:44:30

标签: javascript if-statement recursion

我正在尝试编写一个将金额转换为指定数量的硬币的函数。为此我自己调用一个函数(我认为这是递归编程?)。我有两个问题。

  1. 当我在else语句的if部分调用该函数时,我收到错误消息。 “超出最大调用堆栈大小”?不确定为什么这是因为上面的调用是相同的,并且在第二次调用被注释掉时工作正常。

  2. 此外,当第二个调用被注释掉并且函数运行时,变量total应该在每次调用时增加1。但是它没有超过1.我认为这可能是因为每次调用时变量都在顶部重置为0。但是,remainder变量也设置为0,每次都会减小其值。

  3. 有人能解释这里发生了什么吗?这个问题最好如何解决?

    谢谢

    function amountCoins(amt, coins) {
    
    var remainder = 0;
    total = 0;
    
    if(amt >= coins[0]) {
        total += 1;
        remainder = (amt - coins[0]); 
        return amountCoins(remainder, coins);
    } else {
        coins.shift();
        //return amountCoins(remainder,coins);
    
    }
    alert(total);
    }
    
    amountCoins(121,[20,15,6,1]);
    

6 个答案:

答案 0 :(得分:1)

您可以使用.reduce()作为替代方案。

我们并不需要简单数学可以处理它的循环。

var total = [20,15,6,1].reduce(function(obj, denomination) {
    return {
        total: obj.total + Math.floor(obj.amount / denomination),
        amount: obj.amount % denomination
    };
}, {amount:121, total:0}).total;

或迭代数组。

var arr = [20,15,6,1], amount = 121, total = 0;

for (var i = 0; i < arr.length; ++i) {
    total += Math.floor(amount / arr[i]);
    amount %= arr[i];
}

答案 1 :(得分:0)

如果我是你,我会使用常规for循环:

var amt = 121;
var coins = [20, 15, 6, 1];

var coinsUsed = {};
var totalCoins = 0;

for (var i = 0; i < coins.length; i++) {
    if (coins[i] <= amt) {
        coinsUsed[coins[i]] = Math.floor(amt / coins[i]);
        amt -= coinsUsed[coins[i]] * coins[i];
        totalCoins += coinsUsed[coins[i]];
    } else {
        coinsUsed[coins[i]] = 0;
    }
}

console.log(coinsUsed, totalCoins);

输出:

Object {
    1: 1, 
    6: 0, 
    15: 0, 
    20: 6
}

7

答案 2 :(得分:0)

问题是您的算法永远不会结束。每个递归函数都必须有一个结束,否则会产生堆栈溢出(xD),因为递归调用存储在堆栈中。

这将是一个解决方案:

function amountCoins(amt, coins, total) {    
    var remainder = 0;
    total = total || 0;   //Default value 0 (for the first call)    
    if(coins.length == 0) return total;   //This is the ending condition (no coins)
    if(amt >= coins[0]) {
       total += 1;
       remainder = (amt - coins[0]); 
       return amountCoins(remainder, coins, total);
    } else {
       coins.shift();
       return amountCoins(remainder, coins, total);
    }   
}
var coins = amountCoins(121,[20,15,6,1]);  //Returns: 6
alert(coins);

正如您所看到的,我将total变成了一个参数,因此我们可以将其存储在来电之中。

希望这会有所帮助。干杯

答案 3 :(得分:0)

我认为这就是你要做的事情:

function amountCoins(amt, coins) {
  var remainder = 0;        
  if(coins.length == 0) {
    return 0;
  } else if(amt >= coins[0]) {
      remainder = (amt - coins[0]); 
      return amountCoins(remainder, coins)+1;
  } else {
      coins.shift();
      return amountCoins(remainder,coins);    
  }
}

var total = amountCoins(121,[20,15,6,1]);
alert(total)

这里有一些事情

  1. 递归算法需要终止条件。即。当函数递归调用自身时,它应该在某个时刻停止链。如果没有,程序将耗尽内存以容纳链中的所有调用。因为这是一个潜在的危险情况,像javascript这样的编程语言限制了递归调用的深度。这就是Maximum call stack size exceeded错误的含义。

    在您的程序中,从逻辑上讲,终止条件是我们的硬币耗尽。所以a coins.length == 0检查返回0总计(反过来构成向上链)将解决问题

  2. 通常在递归算法中,结果向后传递,在调用链上向上传递,而不是存储在外部变量中。因此递增的总值用返回语句表示,如return amountCoins(remainder, coins)+1;

  3. 最后,使用for循环可以很容易地实现这个问题。尝试通过展开递归调用链来思考,你将找到一个循环解决方案。

答案 4 :(得分:0)

对原始代码的此更正将起作用:

function amountCoins(amt, coins, total) {

    total = total || 0; 
    if (amt === 0) return total;

    // throw out all the coins that are too big
    while (amt < coins[0]) coins.shift(); 

    // use the largest coin possible, then recurse
    total += 1;
    remainder = amt - coins[0]; 
    return amountCoins(remainder, coins, total);
}

alert(amountCoins(121,[20,15,6,1])); // alerts 7

它具有避免不必要的if ... else语句的优点,并且逻辑更清晰imo

答案 5 :(得分:0)

您不仅要在没有剩余硬币的情况下返还总数,而且如果最后一个硬币的值大于剩余值,则必须返回总数:

function amountCoins(amt, coins, total) {

    total = total || 0;

    if (coins.length == 0 || (amt < coins[0] && coins.length == 1)) return total;

    if (amt >= coins[0]) {
        total += 1;
        remainder = (amt - coins[0]); 
        return amountCoins(amt - coins[0], coins, total);
    } else {
        coins.shift();
        return amountCoins(remainder, coins, total);
    }
}