JavaScript:递归计数基本案例

Posted

技术标签:

【中文标题】JavaScript:递归计数基本案例【英文标题】:JavaScript: Recursive Countup Base Case 【发布时间】:2022-01-19 22:11:09 【问题描述】:

我目前正在做一个 javascript 练习,要求我创建一个递归函数,该函数从开始数到结束数(包括)进行计数。我已经找到了解决方案,但我一直在尝试使我认为是同义的基本案例起作用,但我无法理解它。

function rangeOfNumbers(startNum, endNum) 
  if (endNum < startNum) 
    return [];
  
  const arr = rangeOfNumbers(startNum, endNum - 1);
  arr.push(endNum);
  return arr;
;

console.log(rangeOfNumbers(1, 5)) = [1, 2, 3, 4, 5]

上面的代码有效,但下面的代码无效:

function rangeOfNumbers(startNum, endNum) 
  if (endNum = startNum) 
    return [endNum];
  
  const arr = rangeOfNumbers(startNum, endNum - 1);
  arr.push(endNum);
  return arr;
;

console.log(rangeOfNumbers(1, 5)) = [1]

后者仅输出带有startNum 的数组。我很困惑为什么它不计算递归的其他堆栈,有人可以向我解释一下吗?

【问题讨论】:

【参考方案1】:

递归是一种函数式遗产,因此将其与函数式风格一起使用会产生最佳效果。这意味着要避免诸如突变、变量重新分配和其他副作用之类的事情 -

function rangeOfNumbers (startNum, endNum) 
  if (startNum > endNum)
    return []
  else
    return [startNum].concat(rangeOfNumbers(startNum + 1, endNum))


console.log(JSON.stringify(rangeOfNumbers(0, 3)))
console.log(JSON.stringify(rangeOfNumbers(3, 7)))
console.log(JSON.stringify(rangeOfNumbers(9, 3)))
[0,1,2,3]
[3,4,5,6,7]
[]

使用函数样式意味着您可以将函数调用替换为 return 值,并且总是得到正确的结果。这使您能够对程序进行推理,就好像它们是公式或equations。如果您使用具有命令式风格的递归,那根本不可能 -

rangeOfNumbers(3,6)
== [3].concat(rangeOfNumbers(4,6))
== [3].concat([4].concat(rangeOfNumbers(5,6)))
== [3].concat([4].concat([5].concat(rangeOfNumbers(6,6))))
== [3].concat([4].concat([5].concat([6].concat(rangeOfNumbers(7,6)))))
== [3].concat([4].concat([5].concat([6].concat([]))))
== [3].concat([4].concat([5].concat([6])))
== [3].concat([4].concat([5,6]))
== [3].concat([4,5,6])
== [3,4,5,6]

你可以写出和纯函数表达式一样的东西——

const range = (start, end) =>
  start > end
    ? []
    : [start, ...range(start + 1, end)]

console.log(JSON.stringify(range(0, 3)))
console.log(JSON.stringify(range(3, 7)))
console.log(JSON.stringify(range(9, 3)))
[0,1,2,3]
[3,4,5,6,7]
[]

这个可以可视化为-

range(3,6)
== [3, ...range(4, 6)]
== [3, ...[4, ...range(5, 6)]]
== [3, ...[4, ...[5, ...range(6, 6)]]]
== [3, ...[4, ...[5, ...[6, ...range(7, 6)]]]]
== [3, ...[4, ...[5, ...[6, ...[]]]]]
== [3, ...[4, ...[5, ...[6]]]]
== [3, ...[4, ...[5, 6]]]
== [3, ...[4, 5, 6]]
== [3, 4, 5, 6]

只需再增加一个条件,我们也可以支持反向范围 -

const range = (start, end) =>
  start > end
    ? range(end, start).reverse()
    : start == end
      ? [start]
      : [start, ...range(start + 1, end)]

console.log(JSON.stringify(range(0, 3)))
console.log(JSON.stringify(range(3, 7)))
console.log(JSON.stringify(range(9, 3)))
[0,1,2,3]
[3,4,5,6,7]
[9,8,7,6,5,4,3]  // <- inverse

最后一个可以可视化为 -

range(9,6)
== range(6,9).reverse()
== [6, ...range(7,9)].reverse()
== [6, ...[7, ...range(8,9)]].reverse()
== [6, ...[7, ...[8, ...range(9,9)]]].reverse()
== [6, ...[7, ...[8, ...[9]]]].reverse()
== [6, ...[7, ...[8, 9]]].reverse()
== [6, ...[7, 8, 9]].reverse()
== [6, 7, 8, 9].reverse()
== [9, 8, 7, 6]

【讨论】:

【参考方案2】:

第二个代码块不起作用的原因是if (endNum = startNum) 行。通过使用单个等号,您将startNum 分配给endNum

要检查是否相等,您可以使用 equality operator (==) 或 strict equality operator (===):

if (endNum === startNum) 
  return [endNum]

【讨论】:

是的,我刚刚意识到 :'(((。谢谢!【参考方案3】:

问题是您使用的是赋值运算符而不是相等运算符。

正确

if (endNum === startNum)

不正确

if (endNum = startNum)

【讨论】:

我太笨了........非常感谢! 我们都这样做。大声笑。

以上是关于JavaScript:递归计数基本案例的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript-函数(调用参数returnarguments匿名回调递归函数)函数案例

javasc面向对象编程

JavaScript计数器+classList使用-纯js案例:全选反选

JavaScript中 BOM操作方法以及递归算法案例

Storm入门2-单词计数案例学习

Java 递归计数