Генерация простых чисел в Java

Генерация простых чисел в Java

1. Вступление

В этом уроке мы покажем различные способы генерации простых чисел с помощью Java.

Если вы хотите проверить, является ли число простым, вотa quick guide о том, как это сделать.

2. Простые числа

Начнем с основного определения. A prime number is a natural number greater than one that has no positive divisors other than one and itself.с

Например, 7 является простым, потому что 1 и 7 являются его единственными положительными целочисленными коэффициентами, тогда как 12 не потому, что имеет делители 3 и 2 в дополнение к 1, 4 и 6.

3. Генерация простых чисел

В этом разделе мы увидим, как эффективно генерировать простые числа, меньшие заданного значения.

3.1. Java 7 и ранее - грубая сила

public static List primeNumbersBruteForce(int n) {
    List primeNumbers = new LinkedList<>();
    for (int i = 2; i <= n; i++) {
        if (isPrimeBruteForce(i)) {
            primeNumbers.add(i);
        }
    }
    return primeNumbers;
}
public static boolean isPrimeBruteForce(int number) {
    for (int i = 2; i < number; i++) {
        if (number % i == 0) {
            return false;
        }
    }
    return true;
}

Как видите,primeNumbersBruteForce перебирает числа от 2 доn и просто вызывает методisPrimeBruteForce(), чтобы проверить, является ли число простым или нет.

Метод проверяет делимость каждого числа на числа в диапазоне от 2 доnumber-1.

If at any point we encounter a number that is divisible, we return false. В конце, когда мы обнаруживаем, что это число не делится ни на одно из его предшествующих чисел, мы возвращаем истину, указывая, что это простое число.

3.2. Эффективность и оптимизация

Предыдущий алгоритм не является линейным и имеет временную сложность O (n ^ 2). Алгоритм также неэффективен, и очевидно, что его можно улучшить.

Давайте посмотрим на условие в методеisPrimeBruteForce().

Если число не является простым, это число можно разложить на два фактора, а именноa иb, т.е. number = а * Ь. If both a and b were greater than the square root of n, a*b would be greater than n.

Поэтому, по крайней мере, один из этих факторов должен быть меньше или равен квадратному корню из числа, и чтобы проверить, является ли число простым, нам нужно проверить только факторы, меньшие или равные квадратному корню из проверяемого числа.

Простые числа никогда не могут быть четными, поскольку четные числа делятся на 2.

Кроме того, простые числа никогда не могут быть четными, поскольку четные числа делятся на 2.

Имея в виду изложенные выше идеи, давайте усовершенствуем алгоритм:

public static List primeNumbersBruteForce(int n) {
    List primeNumbers = new LinkedList<>();
    if (n >= 2) {
        primeNumbers.add(2);
    }
    for (int i = 3; i <= n; i += 2) {
        if (isPrimeBruteForce(i)) {
            primeNumbers.add(i);
        }
    }
    return primeNumbers;
}
private static boolean isPrimeBruteForce(int number) {
    for (int i = 2; i*i < number; i++) {
        if (number % i == 0) {
            return false;
        }
    }
    return true;
}

3.3. Использование Java 8

Давайте посмотрим, как мы можем переписать предыдущее решение, используя идиомы Java 8:

public static List primeNumbersTill(int n) {
    return IntStream.rangeClosed(2, n)
      .filter(x -> isPrime(x)).boxed()
      .collect(Collectors.toList());
}
private static boolean isPrime(int number) {
    return IntStream.rangeClosed(2, (int) (Math.sqrt(number)))
      .filter(n -> (n & 0X1) != 0)
      .allMatch(n -> x % n != 0);
}

3.4. Использование сита Эратосфена

Есть еще один эффективный метод, который может помочь нам эффективно генерировать простые числа, и он называется «Сито Эратосфена». Его эффективность по времени составляет O (n logn).

Давайте посмотрим на шаги этого алгоритма:

  1. Создайте список последовательных целых чисел от 2 доn: (2, 3, 4,…, n)

  2. Сначала пустьp равно 2, первому простому числу

  3. Начиная сp, отсчитывайте с шагомp и отметьте каждое из этих чисел больше, чемp в списке. Эти цифры будут 2p, 3p, 4p и т. Д .; обратите внимание, что некоторые из них, возможно, уже отмечены

  4. Найдите в незаметном списке первое число большеp. Если такого номера не было, остановитесь. В противном случае, пустьp теперь равно этому числу (которое является следующим простым числом), и повторите с шага 3

В конце, когда алгоритм завершает работу, все числа в списке, которые не отмечены, являются простыми числами.

Вот как выглядит код:

public static List sieveOfEratosthenes(int n) {
    boolean prime[] = new boolean[n + 1];
    Arrays.fill(prime, true);
    for (int p = 2; p * p <= n; p++) {
        if (prime[p]) {
            for (int i = p * 2; i <= n; i += p) {
                prime[i] = false;
            }
        }
    }
    List primeNumbers = new LinkedList<>();
    for (int i = 2; i <= n; i++) {
        if (prime[i]) {
            primeNumbers.add(i);
        }
    }
    return primeNumbers;
}

3.5. Рабочий пример сита Эратосфена

Посмотрим, как это работает для n = 30.

image

Рассмотрите изображение выше, вот проходы, сделанные алгоритмом:

  1. Цикл начинается с 2, поэтому мы оставляем 2 без отметки и отмечаем все делители 2. Он отмечен на изображении красным цветом

  2. Цикл перемещается на 3, поэтому мы оставляем 3 без отметки и отмечаем все делители 3, которые еще не отмечены. Он отмечен на изображении зеленым цветом

  3. Цикл переходит на 4, он уже отмечен, поэтому продолжаем

  4. Цикл перемещается на 5, поэтому мы оставляем 5 без отметки и отмечаем все делители 5, которые еще не отмечены. Он отмечен на изображении фиолетовым цветом.

  5. Мы продолжаем вышеуказанные шаги, пока цикл не будет равен квадратному корню изn

4. Заключение

В этом быстром уроке мы проиллюстрировали способы, которыми мы можем генерировать простые числа до значения N.

Реализацию этих примеров можно найти вover on GitHub.