Поэтому я написал код для внедрения сита эратосфенов и он хорошо работает для небольших входов !! Как только я беру n до около 1000000000, это показывает и ошибки, HeapMemoryOutOfSpace. Я здесь в блоке и не могу понять, как заставить его работать на такие большие ценности. Есть ли какая-то оптимизация, которая может быть сделана для этого? Это для онлайн-судьи, поэтому максимальное значение n является тем, которое я уже упоминал. Это не для конкуренции и только для моей собственной практики. Любая помощь будет оценена!
import java.io.*;
class PrimeGenerator
{
public static void main(String args[])
{
try
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
while(t--!=0)
{
String k[] = br.readLine().split(" ");
int m = Integer.parseInt(k[0]);
int n = Integer.parseInt(k[1]);
long arr[] = new long[n+2];
for(long a=2;a<=n;a++)
{
arr[(int)a] = 1;
}
for(long a=2;a*a<=n;a++)
{
if(arr[(int)a]==1)
{
for(long b=a;b*a<=n;b++)
{
arr[(int)(a*b)]=0;
}
}
}
for(int a=2;a<=n;a++)
{
if(arr[a]==1&&arr[a]>=m)
{
System.out.println(a);
}
}
System.out.println();
}
}
catch(Throwable e)
{
e.printStackTrace();
}
}
}
Opetion уже указал на несколько структурных проблем с вашим кодом; некоторые биты программы вообще не имеют никакого смысла (например, if (arr[a] == 1 && arr[a] >= m)
). Не говоря уже о том, что код не реализует Сито Эратосфена, хотя он использует аналогичную логику. Эратосфенс удаляет кратность простого числа p, начиная с индекса p * p, а затем увеличивая на p (т.е. Добавляя аддитивно).
Два наблюдения, предполагая, что это что-то вроде проблемы SPOJ PRIME1, где вы должны печатать простые числа между M и N:
(1) Вы используете одно 64-разрядное целое (Java long
) для представления каждого номера кандидата вместо одного бита. Дальнейшее экономия пространства и времени возможно за счет исключения всех четных чисел из массива, при необходимости, притянув номер 2 из тонкого воздуха. В бит-упакованном представлении только для коэффициентов требуется только 1/128-е место, которое вы используете сейчас. В java.util.BitSet
тяжелая работа уже выполнена.
(2) Для просеивания чисел в диапазоне [M, N] нет необходимости просеивать все числа между 2 (или 3) и N. На самом деле, такие задачи, как SPOJ, предназначены для того, чтобы сделать вас тайм-аут, если вы попробуете это, даже несмотря на то, что он выполнен с хорошим чистым высокопроизводительным кодом. Для просеивания диапазона [M, N] вам понадобятся только потенциальные первичные коэффициенты вплоть до sqrt(N)
которые составляют всего несколько тысяч, и массив размеров (N-M+1)
для фактического просеивания. Или (NM)/2
, для сита с шансом. Это займет всего несколько миллисекунд и не так много места.
Для SPOJ вам даже не нужно использовать представления упакованных бит или простое рассеивание. Просто сосредоточившись только на оконном просеивании, вы можете легко справиться с задачей, имея свободное пространство и время.
Вам нужно настроить JVM и увеличить размер кучи.
Если вы запускаете программу на консоли, вы можете увеличить размер следующим образом:
java -Xmx6g myprogram
Эта команда увеличивает размер кучи до 6 гигабайт, увеличивая это независимо от вашей системы.
Если вы используете eclipse или другую среду IDE, вам нужно будет найти, как настроить JVM для запуска этой программы в вашей среде IDE, но она, вероятно, будет напоминать приведенную выше команду.
Для простых чисел до 1000000000 вам не нужно увеличивать размер кучи в правильной реализации.
Некоторые проблемы с вашей реализацией Сито Эратосфена:
Зачем использовать longs, когда вы просто сохраняете 0 и 1?
Существует примитивный тип, который использует только 0 и 1 (false и true), называемый boolean.
Зачем снова пересчитывать каждый премьер?
Вы можете рассчитать каждый простой штрих один раз (максимум до максимального числа), а затем просто проверить список или распечатать их все.
1000000000
скоро ? Сколько вы предсказываете, вы должны вписаться в вашу оперативную память.