注:以下のバージョン 2 では、エラトステネスのふるいを使用しています。私が最初に尋ねたことに役立ついくつかの回答があります。エラトステネスの篩法を選択して実装し、質問のタイトルとタグを適切に変更しました。助けてくれたみんなに感謝します!
序章
指定された上限よりも小さい素数を含む int の配列を生成する、この手の込んだ小さなメソッドを作成しました。とてもよく効きますが、気になることがあります。
メソッド
private static int [] generatePrimes(int max) {
int [] temp = new int [max];
temp [0] = 2;
int index = 1;
int prime = 1;
boolean isPrime = false;
while((prime += 2) <= max) {
isPrime = true;
for(int i = 0; i < index; i++) {
if(prime % temp [i] == 0) {
isPrime = false;
break;
}
}
if(isPrime) {
temp [index++] = prime;
}
}
int [] primes = new int [index];
while(--index >= 0) {
primes [index] = temp [index];
}
return primes;
}
私の懸念
私の懸念は、メソッドが返す要素の最終的な数に対して大きすぎる配列を作成していることです。問題は、指定された数よりも小さい素数の数を正しく推測する良い方法がわからないことです。
集中
これは、プログラムが配列を使用する方法です。これは私が改善したいものです。
- 制限未満のすべての数値を保持するのに十分な大きさの一時配列を作成します。
- 生成した数を数えながら、素数を生成します。
- 素数だけを保持するのに適切な次元の新しい配列を作成します。
- 巨大な配列から各素数を正しい次元の配列にコピーします。
- 生成した素数だけを保持する正しい次元の配列を返します。
質問
-
両方の配列を反復処理して要素を 1 つずつコピーすることなく、
temp[]
ゼロ以外の要素を持つチャンク全体を (一度に) コピーできます か?primes[]
- インスタンス化時に次元を要求するのではなく、要素が追加されるにつれて成長できるプリミティブの配列のように動作するデータ構造はありますか? プリミティブの配列を使用する場合と比較して、パフォーマンスはどの程度低下しますか?
バージョン 2 ( Jon Skeetに感謝):
private static int [] generatePrimes(int max) {
int [] temp = new int [max];
temp [0] = 2;
int index = 1;
int prime = 1;
boolean isPrime = false;
while((prime += 2) <= max) {
isPrime = true;
for(int i = 0; i < index; i++) {
if(prime % temp [i] == 0) {
isPrime = false;
break;
}
}
if(isPrime) {
temp [index++] = prime;
}
}
return Arrays.copyOfRange(temp, 0, index);
}
エラストステネスのふるいを使用するバージョン 3 ( Paul Tomblinに感謝) :
private static int [] generatePrimes(int max) {
boolean[] isComposite = new boolean[max + 1];
for (int i = 2; i * i <= max; i++) {
if (!isComposite [i]) {
for (int j = i; i * j <= max; j++) {
isComposite [i*j] = true;
}
}
}
int numPrimes = 0;
for (int i = 2; i <= max; i++) {
if (!isComposite [i]) numPrimes++;
}
int [] primes = new int [numPrimes];
int index = 0;
for (int i = 2; i <= max; i++) {
if (!isComposite [i]) primes [index++] = i;
}
return primes;
}