Нахождение составных чисел

У меня есть ряд случайных чисел. Диапазон фактически определяется пользователем, но он может составлять до 1000 целых чисел. Они размещены в этом:

vector<int> n

и значения вставляются следующим образом:

srand(1);

for (i = 0; i < n; i++)
  v[i] = rand() % n;

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

void sieve(vector<int> v, int n)
{
  int i,j;

  for(i = 2; i <= n; i++)
     {
        cout << i << " % ";
        for(j = 0; j <= n; j++)
           {
              if(i % v[j] == 0)
                 cout << v[j] << endl;
           }
     }
}

Этот метод обычно работал, когда у меня была только серия чисел от 0 до 1000, но, похоже, он не работает сейчас, когда у меня есть числа не по порядку и их дубликаты. Есть ли лучший способ найти непростые числа в векторе? У меня возникает соблазн просто создать еще один вектор, заполнить его n числами и таким образом найти непростые числа, но будет ли это неэффективно?

Хорошо, поскольку диапазон составляет от 0 до 1000, мне интересно, проще ли просто создать вектор с отсортированными 0-n, а затем использовать сито для поиска простых чисел, приближается ли это?

void sieve(vector<int> v, BST<int> t, int n)
{
  vector<int> v_nonPrime(n);
  int i,j;
  for(i = 2; i < n; i++)
      v_nonPrime[i] = i;

  for(i = 2; i < n; i++)
     {

        for(j = i + 1; j < n; j++)
           {
              if(v_nonPrime[i] % j == 0)
                 cout << v_nonPrime[i] << endl;
           }
     }
}

person Doug    schedule 29.10.2008    source источник
comment
Ах, и там есть подкрадывающаяся ошибка. Вы должны передать вектор в int в качестве ссылки, иначе вы не сможете использовать результаты вне sieve ().   -  person mstrobl    schedule 30.10.2008
comment
Также вы должны использовать push_back, а не v [i] =, поскольку вектор начинается с размера 0.   -  person Motti    schedule 30.10.2008
comment
Ах, я только что увидел, что неправильно прочитал код: v используется не для сохранения результатов, а для ввода данных в метод. Тем не менее, ссылка спасает вашу программу от копирования v.size () числа целых чисел, выделения и освобождения.   -  person mstrobl    schedule 30.10.2008
comment
кстати, не простые числа называются составными   -  person devin    schedule 18.11.2009


Ответы (9)


В этом коде:

if(i % v[j] == 0)
  cout << v[j] << endl;

Вы тестируете свой индекс, чтобы увидеть, делится ли он на v [j]. Я думаю, вы хотели сделать наоборот, а именно:

if(v[j] % i == 0)

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

person Jeremy    schedule 29.10.2008
comment
хамм. Я думаю, вы действительно хотите, чтобы if ((v [j]% i) == 0) получал правильные результаты. - person EvilTeach; 14.01.2009
comment
@EvilTeach:% имеет более высокий приоритет, чем ==. - person ; 06.10.2010

Во-первых, я думаю, что Кнут сказал это первым: преждевременная оптимизация является причиной многих ошибок. Сначала сделайте медленную версию, а затем выясните, как сделать ее быстрее.

Во-вторых, для внешнего цикла вам действительно нужно перейти к sqrt (n), а не к n.

person mmr    schedule 29.10.2008

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

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

Генерация простых чисел лучше всего выполняется ситом Erathostenes Sieve - можно найти множество примеров этого алгоритма.

person xtofl    schedule 29.10.2008
comment
Если у вас есть набор простых чисел, вы просто проверяете, есть ли число, не нужно пытаться делить на каждое. - person Motti; 30.10.2008

Вам следует попробовать использовать простое сито. Вам нужно знать максимальное число для создания сита (O(n)), а затем вы можете построить набор простых чисел в этом диапазоне (O(max_element) или, как указано в задаче O(1000) == O(1))) и проверить, входит ли каждое число в набор простых чисел.

person Motti    schedule 29.10.2008

Ваш код просто неправильный. Во-первых, вы тестируете i% v [j] == 0, который является обратным и также объясняет, почему вы получаете все числа. Во-вторых, ваш вывод будет содержать дубликаты, поскольку вы тестируете и выводите каждый входной номер каждый раз, когда он не проходит (сломанный) тест на делимость.

Другие предложения:

Использование n в качестве максимального значения в векторе и количества элементов в векторе сбивает с толку и бессмысленно. Вам не нужно передавать количество элементов в векторе - вы просто запрашиваете размер вектора. И вы можете довольно быстро вычислить максимальное значение (но если вы знаете его заранее, вы можете также передать его).

Как упоминалось выше, вам нужно только проверить sqrt (n) [где n - максимальное значение в векторе]

Вы можете использовать сито для генерации всех простых чисел до n, а затем просто удалить эти значения из входного вектора, как также было предложено выше. Это может быть быстрее и легче понять, особенно если вы где-то храните простые числа.

Если вы собираетесь тестировать каждое число индивидуально (я полагаю, используя обратное сито), я предлагаю тестировать каждое число индивидуально, по порядку. ИМХО это будет легче понять, чем то, как вы это написали - проверка каждого числа на делимость на k ‹n для постоянного увеличения k.

person Rodyland    schedule 29.10.2008

Идея решета, которую вы пытаетесь реализовать, зависит от того факта, что вы начинаете с простого (2) и вычеркиваете множество этого числа, поэтому все числа, зависящие от простого числа «2», заранее исключаются.

Это потому, что все непростые числа можно разложить на простые числа. В то время как простые числа не делятся по модулю 0, если вы не разделите их на 1 или сами по себе.

Итак, если вы хотите положиться на этот алгоритм, вам понадобится какое-то средство для фактического восстановления этого свойства алгоритма.

person mstrobl    schedule 29.10.2008

У вашего кода много проблем:

  1. Если вы хотите проверить, является ли ваше число простым или непростым, вам нужно будет проверить v [j]% i == 0, а не наоборот.
  2. Вы не проверяли, делится ли ваше число само по себе
  3. Вы продолжаете проверять свои числа снова и снова. Это очень неэффективно.

Как предлагали другие ребята, вам нужно сделать что-то вроде Решета Эратосфена.

Таким образом, псевдо-код C для вашей проблемы будет (я еще не запускал это через компиляторы, поэтому, пожалуйста, игнорируйте синтаксические ошибки. Этот код предназначен только для иллюстрации алгоритма)

vector<int> inputNumbers;

// First, find all the prime numbers from 1 to n
bool isPrime[n+1] = {true};
isPrime[0]= false;
isPrime[1]= false;
for (int i = 2; i <= sqrt(n); i++)
{
  if (!isPrime[i])
    continue;
  for (int j = 2; j <= n/i; j++)
    isPrime[i*j] = false;
}

// Check the input array for non-prime numbers
for (int i = 0; i < inputNumbers.size(); i++)
{
   int thisNumber = inputNumbers[i];
   // Vet the input to make sure we won't blow our isPrime array
   if ((0<= thisNumber) && (thisNumber <=n))
   {
      // Prints out non-prime numbers
      if (!isPrime[thisNumber])
         cout<< thisNumber;
   }
}
person Community    schedule 29.10.2008

сортировка числа в первую очередь может быть хорошим началом - вы можете сделать это за время nLogN. Это небольшое дополнение (я думаю) к вашей другой проблеме - поиску того, является ли число простым.
(на самом деле, с небольшим набором таких чисел вы можете выполнить сортировку намного быстрее с копией размера вектора / набора и выполнить сортировку по хешу / ведру / что угодно)

Затем я бы нашел наивысшее число в наборе (я предполагаю, что числа могут быть неограниченными - верхний предел неизвестен до вашей сортировки - или сделать один проход, чтобы найти максимальное значение)

затем пойти с ситом - как говорили другие

person Tim    schedule 29.10.2008

Джереми прав, основная проблема - это ваш i % v[j] вместо v[j] % i.

Попробуй это:

void sieve(vector<int> v, int n) {
  int i,j;

  for(j = 0; j <= n; j++) {
    cout << v[j] << ": ";

    for(i = 2; i < v[j]; i++) {
      if(v[j] % i == 0) {
        cout << "is divisible by " << i << endl;
        break;
      }
    }

    if (i == v[j]) {
      cout << "is prime." << endl;
    }
  }
}

Это не оптимально, потому что оно пытается разделить на все числа меньше v[j], а не только на квадратный корень из v[j]. И это попытка деления на все числа, а не только на простые числа.

Но это сработает.

person Jamie    schedule 29.10.2008