正在查找复合数字

Finding composite numbers

本文关键字:数字 复合 查找      更新时间:2023-10-16

我有一系列随机数。范围实际上是由用户决定的,但它最多可以是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;
           }
     }
}

在此代码中:

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

你正在测试你的索引,看看它是否可以被v[j]整除。我想你是想换一种方式,即:

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

现在,你正在打印i的随机除数。你没有打印出已知不是素数的随机数。此外,你的输出中会有重复,也许这没关系。

首先,我认为Knuth首先说了:过早优化是导致许多错误的原因。先制作慢版本,然后想办法让它更快。

第二,对于外循环,你只需要去sqrt(n)而不是n。

基本上,你有很多不相关的数字,所以你必须检查每个数字是否是素数。

如果你事先知道数字的范围,你就可以生成可以出现在该范围内的所有素数(或其平方),并测试容器中的每个数字是否可以被任何一个生成的素数整除。

生成素数最好通过Erathostenes筛来完成——该算法有很多例子。

您应该尝试使用素数筛。你需要知道创建筛子的最大数(O(n)),然后你可以在这个范围内建立一组素数(O(max_element)或问题状态为O(1000) == O(1))),并检查每个数是否在素数集中。

您的代码完全错误。首先,您正在测试i%v[j]==0,这是向后的,也解释了为什么您得到所有数字。第二,当你测试并输出每个输入数字时,你的输出将包含重复的数字,每次它未通过(坏的)可分割性测试。

其他建议:

使用n作为向量中的最大值和向量中的元素数量是令人困惑和毫无意义的。您不需要传入向量中的元素数量,只需查询向量的大小即可。你可以很快算出最大值(但如果你提前知道,你也可以把它传进去)。

如上所述,您只需要测试sqrt(n)[其中n是vecotr中的最大值]

你可以使用一个筛子来生成n以内的所有素数,然后从输入向量中删除这些值,如上所述。这可能更快更容易理解,尤其是如果你把素数存储在某个地方。

如果你要单独测试每个数字(我想,使用反向筛选),那么我建议按顺序单独测试每个数。IMHO,这将比你写它的方式更容易理解——测试每个数字是否可被k<n表示不断增加的k。

您试图实现的筛选的想法取决于您从素数(2)开始并划掉该数的多个-因此所有依赖于素数"2"的数都会被预先排除。

这是因为所有的非素数都可以分解为素数。而素数不能用模0整除,除非你把它们除以1或它们自己。

所以,如果你想依赖这个算法,你需要一些手段来实际恢复算法的这个属性。

您的代码似乎有很多问题:

  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;
   }
}

首先对数字进行排序可能是一个好的开始——您可以在nLogN时间内完成这一操作。这是对你的另一个问题的一个小补充(我认为),即寻找一个数字是否是素数
(实际上,使用这样的一小组数字,你可以用向量/集大小的副本更快地进行排序,并进行哈希/桶排序/其他任何操作)

然后我会找到集合中最高的数字(我假设这些数字可以是无限的——在你排序之前不知道上限——或者只需一次就可以找到最大值)

然后进行筛选-正如其他人所说的

Jeremy是对的,基本问题是你的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]的平方根。它正在尝试用所有的数字除数,而不仅仅是素数。

但它会起作用的。