【问题标题】:Finding composite numbers寻找合数
【发布时间】:2008-10-29 21:02:08
【问题描述】:

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

【问题讨论】:

  • 啊,那里有一个蠕动的错误。您应该将向量作为参考传递给 int,否则您将无法在 sieve() 之外使用结果。
  • 另外你应该使用 push_back 而不是 v[i] = 因为向量从 0 开始。
  • 啊,我刚刚看到我看错了代码:v不是用来保存任何结果,而是为方法提供输入。尽管如此,引用可以让您的程序免于复制 v.size() 个整数、分配和解除分配。
  • 顺便说一下,非素数被称为复合

标签: c++ primes sieve


【解决方案1】:

在这段代码中:

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

您正在测试您的索引以查看它是否可以被 v[j] 整除。我认为您的意思是反过来,即:

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

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

【讨论】:

  • 嗯。我认为你真的希望 if ((v[j] %i) == 0) 得到正确的结果。
  • @EvilTeach: % 的优先级高于 ==。
【解决方案2】:

首先,我认为 Knuth 首先说过:过早的优化是许多错误的原因。先做慢版本,再想办法让它变快。

其次,对于你的外循环,你真的只需要去 sqrt(n) 而不是 n。

【讨论】:

    【解决方案3】:

    基本上,您有很多不相关的数字,因此对于每个数字,您都必须检查它是否为素数。

    如果您事先知道数字的范围,您可以生成所有 可以 出现在该范围(或其 sqrt)内的素数,并测试容器中的每个数字的可分性任何一个生成的素数。

    生成素数最好由 Erathostenes Sieve 完成 - 该算法有很多示例。

    【讨论】:

    • 如果你有一组素数,你只需检查数字是否存在,无需尝试逐个划分。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      其他建议:

      使用n作为向量中的最大值和向量中的元素个数是令人困惑和毫无意义的。您不需要传入向量中的元素数量 - 您只需查询向量的大小。而且您可以相当快地计算出最大值(但如果您提前知道它,您不妨将它传递进去)。

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

      您可以使用筛子生成直到 n 的所有素数,然后从输入向量中删除这些值,如上文所建议的那样。这可能会更快更容易理解,尤其是如果您将素数存储在某个地方。

      如果您要单独测试每个数字(我猜是使用反筛),那么我建议按顺序单独测试每个数字。恕我直言,它比您编写它的方式更容易理解 - 测试每个数字的 k

      【讨论】:

        【解决方案6】:

        您尝试实施的筛子的想法取决于您从质数 (2) 开始并删除该数字的多个这一事实 - 因此,所有依赖于质数“2”的数字都被预先排除。

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

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

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

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

            然后我会在集合中找到最大的数字(我假设数字可以是无限的 - 在你排序之前不知道上限 - 或者单次通过以找到最大值)

            然后用筛子去 - 正如其他人所说的那样

            【讨论】:

              【解决方案9】:

              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] 的平方根。它正在尝试除以所有数字,而不仅仅是素数。

              但它会起作用。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2019-09-29
                • 1970-01-01
                • 1970-01-01
                • 2011-01-13
                • 1970-01-01
                • 2012-07-26
                • 2013-10-07
                • 2016-12-13
                相关资源
                最近更新 更多