【问题标题】:How to find prime numbers in C using recursion如何使用递归在C中找到素数
【发布时间】:2015-10-09 02:17:24
【问题描述】:

我正在编写一个程序来使用递归查找 C 中的素数。这是我编写的程序。

#include<stdio.h>
#include<conio.h>

void rec(int, int);
int main()
{
    rec(2,2);
    getch();
    return 0;
}
void rec(int n, int x)
{
    if(x>999)
        return;
    if(n==x)
    {
        printf("%d ,", x);
        rec(2,x+1);
        return;
    }
    if(x%n==0)
    {
        rec(2,x+1);
        return;
    }
    rec(n+1,x);
}

我不知道它有什么问题,它运行良好,直到 887 之后崩溃。要检查,只需将x&gt;999 替换为x&gt;300,它会起作用,但不适用于x&gt;999。请告诉程序中的错误,而不是编写一个全新的程序。

【问题讨论】:

  • 是的,但是,我认为我的程序中没有无限递归。
  • 那你觉得问题出在哪里。大递归会导致段错误吗?
  • 我认为,当我检查超过 887 的素数时,没有。调用次数超过了它的可用内存,它试图抢占内存,但堆栈已满,所以它崩溃了。那么有没有其他方法可以找到超过 887 的素数?
  • 尝试将n除以所有素数2到sqrt(n)。要找到大于 3 的素数,请将 2 加到前一个素数上并递归测试它是否是素数。所以你有 2 个函数 bool is_prime(n)unsigned next_prime(n) 互相调用。

标签: c recursion crash stack-overflow primes


【解决方案1】:

可能超出递归深度。

递归深度似乎与极限的平方成正比。
试试

#include <stdio.h>
int depth = 0;
int maxdepth = 0;

void rec(int n, int x) {
  depth++;
  if (depth > maxdepth) maxdepth = depth;
  if (x > 860) {
    depth--;
    return;
  }
  if (n == x) {
    printf("%d ,", x);
    rec(2, x + 1);
    depth--;
    return;
  }
  if (x % n == 0) {
    rec(2, x + 1);
    depth--;
    return;
  }
  rec(n + 1, x);
  depth--;
}

int main(void) {
  rec(2, 2);
  printf("\n depth %d maxdepth %d\n", depth, maxdepth);
  return 0;
}

最大深度 60099(限制为 860)

代码需要一种深度较少的方法。

尝试将n 除以所有素数 2 到 sqrt(n)。如果是偶数,则它只有 2 的素数。否则,如果低于 7,则如果不是 1,则它是素数。否则要找到高于 7 的素数,将前一个素数候选者加 2 并递归测试它是否为素数。所以你有 2 个函数 bool is_prime(n)unsigned next_prime(n) 互相调用。

最大深度:所有 1000 个为 3

就像 OP 的 self description,在这种情况下“懒得再多说。”

【讨论】:

  • 嘿嘿嘿,这也够了,我明白了。谢谢:)
  • 递归的深度是否依赖于 RAM 并且对于给定的 RAM 总是恒定的?
  • @Siraj 不,C 没有指定最大堆栈深度。 C 甚至没有指定堆栈必须存在。递归深度限制是非常特定于平台的。假设更多的 RAM 允许更大的堆栈深度当然是合理的。然而,堆栈深度可能会随着 RAM 的恒定而变化。
【解决方案2】:
#include<stdio.h>

void rec(int test_number, int prime_index);

int main(void){
    rec(2, 0);

    return 0;
}

void rec(int n, int i){
    static int prime[500], cp;//for memorize
    if(n > 999)
        return;
    if(prime[i] == 0 || prime[i]*prime[i] > n){//prime[i]*prime[i] > n : To reduce the depth of recursion by narrowing the upper limit of the test.
        printf("%d, ", n);
        prime[cp++] = n;
        rec(n + 1 + (n != 2), 0);//n != 2 : Avoid an even number of other than 2
        return;
    }
    if(n % prime[i]==0){
        rec(n + 1 + (n != 2), 0);
        return;
    }
    rec(n, i+1);
}

【讨论】:

  • 请对下面的评论做一点解释: //prime[i]*prime[i] > n : 通过缩小测试的上限来减少递归的深度。
  • @Siraj 将 n 除以所有素数 2 到 sqrt(n)。
  • n = ab 如果 n 可以被 a 整除。 b √n
【解决方案3】:

您可以尝试使用以下代码查找介于 1 和给定整数 N(范围内的素数列表)之间的素数:

#include<stdio.h>
void main()
{
    int n,flag=0,i,j;
    printf("Enter range of prime number : ");
    scanf("%d",&n);
    printf("\nPrime numbers are : ");
    for(i=1;i<n;i++)
    {
        flag=0;
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                flag=1;
                break;
            }
            else
                flag=0;
        }
        if(flag==0)
            printf("\n%d",i);
    }
}

【讨论】:

    【解决方案4】:

    问题:rec函数在不同条件语句下多次递归导致递归深度增加。

    解决方案:通过在 main 函数中有一个循环以在 rec 函数中传递检查中的数字(素数或非素数),减少条件语句下 rec 函数的使用。

    #include<stdio.h>
    void rec(int,int);
    int main()
    {
        int i=2;
        while(i<=1000) //passing 2,3,4...,1000 (one by one) in rec function to check if it is prime or not
        {
            rec(2,i);
            i++;
        }
    }
    void rec(int n,int x)
    {
        if(n==x) //if number(n) by which divisibility is checked and number(x or i) which is under checking gets equal then number(x or i) is proved as prime and get printed
            printf("%d, ", x);
        else if(x%n!=0) //if number(x or i) under checking is not divisible by number(n) then call rec function again to check divisibility of number(x) by number(n+1)
            rec(n+1,x);
    //if number(x or i) under checking is divisible by number(n) at any stage then return to main function and next number(i++ or new x) is passed to rec function to check if it is prime or not
    }
    

    建议:递归函数很有趣。但是使用递归函数或任何简单的方法打印素数到很大的限制(10^6)非常慢。使用 Eratosthenes 筛法(快速、简单且有趣)或它的一些 修改版(最快) 可以非常快速地打印任何程度的素数。也尝试学习 Sundaram 筛法(也很慢但有趣)和 阿特金筛法(快速而有趣但复杂)。

    【讨论】:

      猜你喜欢
      • 2016-09-02
      • 1970-01-01
      • 2020-07-03
      • 2017-05-20
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 2011-05-02
      相关资源
      最近更新 更多