문제
나는 임의의 숫자 범위를 가지고 있습니다.범위는 실제로 사용자가 결정하지만 최대 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는 먼저 말했습니다. 조기 최적화는 많은 버그의 원인입니다. 느린 버전을 먼저 만든 다음 더 빨리 만드는 방법을 알아냅니다.
둘째, 외부 루프의 경우 실제로 n이 아닌 SQRT (n)로 이동하면됩니다.
기본적으로, 당신은 관련이없는 숫자가 많기 때문에 각 숫자에 대해 그것이 프라임인지 확인해야합니다.
미리 숫자의 범위를 알고 있다면 모든 소수를 생성 할 수 있습니다. ~할 수 있다 해당 범위 (또는 SQRT)에서 발생하고 생성 된 프라임 중 하나에 의해 컨테이너의 모든 숫자를 테스트하십시오.
프라임 생성은 Erathostenes Sieve에 의해 가장 잘 이루어집니다. 그 알고리즘에 대한 많은 예제를 찾을 수 있습니다.
당신은 a를 사용해야합니다 프라임 체. 체를 만들기위한 최대 숫자를 알아야합니다 (O(n)
) 그런 다음 해당 범위에서 일련의 프라임을 만들 수 있습니다 (O(max_element)
또는 문제가 나타납니다 O(1000) == O(1)
)) 및 각 숫자가 프라임 세트에 있는지 확인하십시오.
당신의 코드는 단지 명백한 잘못입니다. 먼저, i % v [j] == 0을 테스트하고 있는데, 이는 뒤로이며 모든 숫자를 얻는 이유를 설명합니다. 둘째, 출력은 (깨진) 분할 성 테스트에 실패 할 때마다 각 입력 번호를 테스트하고 출력 할 때 중복을 포함합니다.
기타 제안 :
n을 벡터의 최대 값으로 사용하고 벡터의 요소 수는 혼란스럽고 무의미합니다. 벡터의 요소 수를 전달할 필요가 없습니다. 벡터의 크기를 쿼리합니다. 그리고 당신은 최대를 상당히 빨리 알아낼 수 있습니다 (그러나 미리 알고 있다면 그것을 전달할 수도 있습니다).
위에서 언급했듯이 SQRT (N)로만 테스트하면됩니다. [여기서 N은 Vecotr의 최대 값입니다
체를 사용하여 모든 프라임을 최대 n으로 생성 한 다음 위에서 제안한대로 입력 벡터에서 해당 값을 제거 할 수 있습니다. 특히 프라임을 어딘가에 저장하는 경우 더 빠르고 이해하기 쉬울 수 있습니다.
각 숫자를 개별적으로 테스트하려면 (사용, 추측 및 역 체가) 각 숫자를 개별적으로 테스트하는 것이 좋습니다. IMHO 작성 방식보다 이해하기가 더 쉽습니다. K <N으로 각 숫자를 k <n으로 테스트하면 k k <n입니다.
당신이 구현하려는 체의 아이디어는 당신이 프라임 (2)에서 시작하고 해당 숫자의 멀티 트리트를 교차한다는 사실에 달려 있습니다. 따라서 프라임 "2"에 의존하는 모든 숫자는 미리 배제됩니다.
이는 모든 비 프라임이 프라임으로 인수 될 수 있기 때문입니다. 반면, 프라임은 1으로 나누거나 스스로 나누지 않는 한 모듈로 0과 나눌 수 없습니다.
따라서이 알고리즘에 의존하려면 알고리즘 의이 속성을 실제로 복원해야합니다.
코드는 많은 문제가있는 것 같습니다.
- 숫자가 프라임인지 비 프라임인지 테스트하려면 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 시간 안에 그렇게 할 수 있습니다.그것은 숫자가 소수인지 찾는 문제인 다른 문제에 작은 추가 사항입니다.
(실제로 이와 같은 작은 숫자 세트를 사용하면 벡터/세트 크기의 복사본을 사용하여 훨씬 빠르게 정렬을 수행하고 해시/버킷 정렬 등을 수행할 수 있습니다)
그런 다음 세트에서 가장 높은 숫자를 찾습니다. (숫자는 무제한일 수 있다고 가정합니다. 정렬할 때까지 상한선을 알 수 없습니다. 또는 최대값을 찾기 위해 단일 패스를 수행합니다.)
그런 다음 체를 가지고 가십시오 - 다른 사람들이 말했듯이
제레미는 옳습니다. 기본적인 문제는 당신입니다 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]
. 그리고 그것은 단지 프라임 대신 모든 숫자로 분할을 시도하고 있습니다.
그러나 그것은 효과가있을 것입니다.