我有一系列随机数。范围实际上是由用户决定的,但它最多可以是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或它们自己。
所以,如果你想依赖这个算法,你需要一些手段来实际恢复算法的这个属性。
您的代码似乎有很多问题:
- 如果你想测试你的数字是素数还是非素数,你需要检查v[j]%i==0,而不是相反
- 你没有检查你的数字是否正在除以自己
- 你一次又一次地检查你的号码。这是非常低效的
正如其他人建议的那样,你需要做一些类似埃拉托斯梯尼筛的事情。
因此,您的问题的伪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]
的平方根。它正在尝试用所有的数字除数,而不仅仅是素数。
但它会起作用的。