是一个递归迭代方法比单纯的迭代法,以找出是否一个数是素更好? [英] Is a Recursive-Iterative Method Better than a Purely Iterative Method to find out if a number is prime?

查看:138
本文介绍了是一个递归迭代方法比单纯的迭代法,以找出是否一个数是素更好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在用C这一计划,测试如果数是素。我尚未熟悉算法的复杂性和所有大O的东西,所以我不能确定,如果我的做法,这是迭代和递归的的组合,实际上是比使用纯粹迭代方式。

I made this program in C that tests if a number is prime. I'm as yet unfamiliar with Algorithm complexity and all that Big O stuff, so I'm unsure if my approach, which is a combination of iteration and recursion, is actually more efficient than using a purely iterative method.

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

typedef struct primenode{
    long int key;
    struct primenode * next;
}primenode;

typedef struct{
    primenode * head;
    primenode * tail;
    primenode * curr;
    unsigned long int size;
}primelist;

int isPrime(long int number, primelist * list ,long int * calls, long int * searchcalls);
primenode * primelist_insert(long int prime, primelist * list);
int primelist_search(long int searchval, primenode * searchat, long int * calls);
void primelist_destroy(primenode * destroyat);

int main(){
    long int n;
    long int callstoisprime = 0;
    long int callstosearch = 0;
    int result = 0;
    primelist primes;

    //Initialize primelist
    primes.head = NULL;
    primes.tail = NULL;
    primes.size = 0;

    //Insert 2 as a default prime (optional step)
    primelist_insert(2, &primes);

    printf("\n\nPlease enter a number: ");
    scanf("%d",&n);
    printf("Please wait while I crunch the numbers...");
    result = isPrime(n, &primes, &callstoisprime, &callstosearch);
    switch(result){
        case 1: printf("\n%ld is a prime.",n); break;
        case -1: printf("\n%ld is a special case. It's neither prime nor composite.",n); break;
        default: printf("\n%ld is composite.",n); break;
    }
    printf("\n\n%d calls made to function: isPrime()",callstoisprime);
    printf("\n%d calls made to function: primelist_search()",callstosearch);

    //Print all prime numbers in the linked list
    printf("\n\nHere are all the prime numbers in the linked list:\n\n");
    primes.curr = primes.head;
    while(primes.curr != NULL){
        printf("%ld ", primes.curr->key);
        primes.curr = primes.curr->next;
    }
    printf("\n\nNote: Only primes up to the square root of your number are listed.\n"
                "If your number is negative, only the smallest prime will be listed.\n"
                "If your number is a prime, it will itself be listed.\n\n");

    //Free up linked list before exiting
    primelist_destroy(primes.head);

    return 0;
}

int isPrime(long int number, primelist * list ,long int * calls, long int *searchcalls){
//Returns 1 if prime
//          0 if composite
//          -1 if special case
    *calls += 1;
    long int i = 2;
    if(number==0||number==1){
        return -1;
    }
    if(number<0){
        return 0;
    }
    //Search for it in the linked list of previously found primes
    if(primelist_search(number, list->head, searchcalls) == 1){
        return 1;
    }
    //Go through all possible prime factors up to its square root
    for(i = 2; i <= sqrt(number); i++){ 
        if(isPrime(i, list,calls,searchcalls)){
            if(number%i==0) return 0; //It's not a prime
        }
    }
    primelist_insert(number, list); /*Insert into linked list so it doesn't have to keep checking
                                                if this number is prime every time*/
    return 1;
}

primenode * primelist_insert(long int prime, primelist * list){
    list->curr = malloc(sizeof(primenode));
    list->curr->next = NULL;

    if(list->head == NULL){
        list->head = list->curr;
    }
    else{
        list->tail->next = list->curr;
    }
    list->tail = list->curr;
    list->curr->key = prime;
    list->size += 1;

    return list->curr;
}

int primelist_search(long int searchval, primenode * searchat, long int * calls){
    *calls += 1;
    if(searchat == NULL) return 0;
    if(searchat->key == searchval) return 1;
    return primelist_search(searchval, searchat->next, calls);
}

void primelist_destroy(primenode * destroyat){
    if(destroyat == NULL) return;
    primelist_destroy(destroyat->next);
    free(destroyat);
    return;
}

基本上,很多我所看到的简单primalty测试要做的是:
0.2是一个素数。
1.循环通过从2至一半或数量的平方根的所有整数被测试。
2.如果数字是整除任何东西,突破和返回false;它的复合材料。
3.否则,最后一次迭代后返回true;它的素数。

Basically, a lot of what I've seen simple primalty tests do is: 0. 2 is a prime. 1. Cycle through all integers from 2 to half or the square root of the number being tested. 2. If the number is divisible by anything, break and return false; it's composite. 3. Otherwise, return true after the last iteration; it's prime.

我计算过,你没有要测试的每个数字2的平方根,只是每次的主要的数量,因为所有其他的数字是素数的倍数。因此,函数调用自身,以找出是否一个数字是使用它的模前总理。这工作,但我认为它有点乏味,以保持一遍又一遍的测试所有的素数。
所以,我用一个链表来存储它发现以及每个素,从而使测试primalty之前,程序首先搜索列表中。

I figured that you don't have to test against every number from 2 to the square root, just every prime number, because all other numbers are multiples of primes. So, the function calls itself to find out if a number is prime before using the modulus on it. This works, but I thought it a bit tedious to keep testing all those primes over and over again. So, I used a linked list to store every prime found in it as well, so that before testing primalty, the program searches the list first.

是不是真的更快,更高效的,还是我只是浪费了大量的时间?我没有测试它在我的电脑上,而对于较大的素数它似乎更快,但我不知道。我也不知道,如果它使用显著更多的内存,因为任务管理器只是停留恒定0.7 MB无论我做什么。

Is it really faster, or more efficient, or did I just waste a lot of time? I did test it on my computer, and for the larger primes it did seem faster, but I'm not sure. I also don't know if it uses significantly more memory since Task Manager just stays a constant 0.7 MB whatever I do.

感谢您的答案!

推荐答案

由于程序测试的一个数字,你是在浪费时间试图避免复合材料测试。您可以执行大量的计算,以救一个微薄的模操作。

Since your program tests just one number, you're wasting time trying to avoid testing by composites. You perform a lot of computations to save one meager modulo operation.

如果你在一排素性测试以上几个数字越多,那么它会通过这些素数是有意义的pre-计算素数高达该区间的顶部极限开方和循环测试考生。

If you were testing more than a few numbers in a row for primality, then it would make sense to pre-compute the primes up to a sqrt of the top limit of that range, and cycle through those primes in testing the candidates.

更重要的是将要执行的的偏移埃拉托色尼<筛/ em>的 C $ C $这里 C),发现在给定范围内的素数。埃拉托色尼的筛找到2到N素数的时间复杂度为 O(N日志日志N);和素数达开方审判庭, O(N ^ 1.5 /(日志N)^ 2)(这是慢得多;如的运行时间的比值筛高达1mln相比,100K为10.7倍,22倍VS审理分工; 2mln对1万是2.04x的筛子,2.7倍的审判庭)

Better yet will be to perform an offset sieve of Eratosthenes (C code here), to find the primes in a given range. The time complexity of the sieve of Eratosthenes to find primes from 2 to N is O(N log log N); and trial division by primes up to the sqrt, O(N^1.5 / (log N)^2) (which is much slower; e.g. the ratio of run times for the sieve up to 1mln compared to 100k is 10.7x, vs 22x for trial division; 2mln vs 1 mln is 2.04x for the sieve, 2.7x for the trial division).

伪code的埃拉托色尼的偏移筛:

Pseudocode for the offset sieve of Eratosthenes:

Input: two Integers n >= m > 1

Let k = Floor(Sqrt(n)),
Let A be an array of Boolean values, indexed by Integers 2 to k, and
    B an array of Booleans indexed by Integers from m to n,
    initially all set to True.

for i = 2, 3, 4, ..., not exceeding k:
  if A[i] is True:
    for j = i^2, i^2+i, i^2+2i, ..., not greater than k:
      A[j] := False
    for j = i^2, i^2+i, i^2+2i, ..., between m and n, inclusive:
      B[j] := False

Output: all `i`s such that B[i] is True, are all the primes 
                                     between m and n, inclusive.

一个常见的​​优化是唯一的机会, I = 3,5,7,... ,避免任何偶数从一开始(2已知工作是一个素无论如何,任何偶数是一个复合)。然后 2I ,而不仅仅是的步骤i ,可以在这两个内部循环使用。因此,即使指数从完全排除的处理(一般用浓缩寻址方案, VAL =开始+ 2 * I )。

A common optimization is to work with odds only, i = 3,5,7,..., avoiding any even numbers from the outset (2 is known to be a prime anyway, and any even number is a composite). Then the step of 2i, and not just i, can be used in both inner loops. Thus the even indices are excluded from processing altogether (usually with condensed addressing schemes, val = start + 2*i).

这篇关于是一个递归迭代方法比单纯的迭代法,以找出是否一个数是素更好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆