【问题标题】:Sieve of Eratosthenes in Javascript?Javascript 中的 Eratosthenes 筛法?
【发布时间】:2017-01-05 19:35:19
【问题描述】:

所以我试图将这个伪代码从 Wikipedia 翻译成 Javascript:

Input: an integer n > 1

Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.

for i = 2, 3, 4, ..., not exceeding √n:
  if A[i] is true:
    for j = i^2, i^2+i, i^2+2i, i^2+3i, ..., not exceeding n :
      A[j] := false

Output: all i such that A[i] is true.

这是据我所知:

function getPrimes(num) {
  var a = [];
  for (i=2;i<=num;i++){a.push(true);} 
  for (i=2;i<=Math.sqrt(num);i++){
    for (var j=i*i, coef=0, l=i;j<num-2;coef++){
      j = i*i+coef*l-2;
      a[j]=false;
    } 
    for (i=0;i<a.length;i++){
      if (a[i]){a.splice(i,1,i+2);}
    } 
  }
  return a;
}

getPrimes(10); // returns [2, 3, false, 5, false, 7, false, 9, false]
               // 9 should be false

如您所见,该算法并未捕获所有非质数。知道我错过了什么吗?提前感谢任何想尝试一下的人。

【问题讨论】:

  • 你在内部循环中增加'i',所以外部循环只在 i = 2 时执行。一旦你的第二个内部循环完成,i 就大于 sqrt(10)现在 9.
  • 不要在每次迭代时重新计算Math.sqrt(num),这是一个昂贵的操作。

标签: javascript arrays for-loop scope sieve-of-eratosthenes


【解决方案1】:

您正在覆盖外部循环的i 变量,而第二个内部循环也使用i。所以外循环只运行一次。

为内部循环使用另一个变量,如k,你会得到一个好的结果。

但没有必要将特定的内部循环放置在那里。它只需要真正运行一次,就在返回之前。所以你可以把它移出主循环。

一个小问题是你的第一个内部循环走得太远了,因为j 在循环体中递增,而对j 的测试只有在你已经为a[j] 赋值之后才会发生。 JavaScript 只是在那一刻创建该元素,使数组更长,但如果你能防止这种情况发生会更好

我还将保留数组 a 的前 2 个索引来表示数字 0 和 1,只是为了使您的代码更具可读性:那么您就不再需要那些 +2-2 了。

考虑到所有这些,加上其他一些优化,我建议使用以下 ES6 代码:

function getPrimes(num) {
  var a = [...Array(num+1).keys()]; // =[0,1,...,num]
  a[1] = 0; // 1 is not prime
  var rt = Math.sqrt(num); // calculate only once
  for (i=2;i<=rt;i++){
    for (var j=i*i; j<=num; j+=i) a[j]=0;
  }
  return a.filter(Number); // kick out the zeroes
}
// run it for 30
var a = getPrimes(30); 
// Output
console.log(a);

【讨论】:

  • 我以前没有见过 array.filter() 与类型一起使用。是否是一个 hack 可以解析为 function(input) { return typeof input === 'number' } 以进行回调?
  • filter() 需要一个函数,您可以编写一个内联函数,例如 .filter( function (val) { return Number(value); }。对Number 的调用只会返回数字本身,但由于 0 是假的,因此只会保留非零。所以是的,在这种情况下它只是一个虚拟函数。
  • 有趣。所以它基本上是隐式调用 Number 构造函数。然后零将被视为虚假并被过滤器功能删除。
  • 是的,虽然有一点:它不被称为构造函数,因为你需要使用new Number(...)。如果没有new,它会提供类型转换并返回原始值(不是对象),通常与字符串参数一起使用。
  • 啊,现在更有意义了。非常感谢@trincot
猜你喜欢
  • 2021-12-19
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
  • 2017-01-11
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多