• 素数生成算法小结


    阅读《C语言编程—一本全面的C语言入门教程》一书,看到了质数生成的小程序,特此记录

    1. 直接求解

    这是最简单和无脑的暴力算法了,直接双重循环,复杂度为(O(N^2))

    void prime_generator_1(void)
    {
        int p;
        int d;
        bool isPrime;
    
        for( p = 2; p <= MAX_NUM; ++p)
        {
            isPrime = true;
    
            for( d = 2; d < p; ++ d)
            {
                if(p % d == 0)
                {
                    isPrime = 0;
                    break;
                }
            }
            if( isPrime != false)
            {
                printf("%i ", p);
            }
        }
    
        printf("
    ");
    }
    

    2. 一些改进

    很明显的一个改进是,任何大于2的偶数都不可能是质数,因此,在外循环中p从3开始,每次递增2;内循环与之类似。额外注意的是,2既是偶数,也是质数,需单独处理。

    void prime_generator_2(void)
    {
        int p;
        int d;
        bool isPrime;
    
        printf("%i ", 2);
        for( p = 3; p <= MAX_NUM; p += 2)
        {
            isPrime = true;
    
            for( d = 3; d < p; d += 2)
            {
                if(p % d == 0)
                {
                    isPrime = 0;
                    break;
                }
            }
            if( isPrime != false)
            {
                printf("%i ", p);
            }
        }
    
        printf("
    ");
    }
    

    3. 继续改进

    以上的改进虽然有效,但算法的效率并没有根本性的提高,特别是在产生大型的质数表(>1,000,000),算法的效率至关重要。

    有两个标准可以帮助提高效率

    • 任何一个非质整数都可以分解为多个质数的乘积,也就是说,如果一个数不能被任何质数整除,那么这个数就是一个质数。
    • 任何一个非质数的整数,肯定会有一个小于其平方根的质因数。
    void prime_generator_3(void)
    {
        int primes[MAX_NUM];
        int primeIndex = 2;
        bool isPrime;
    
        primes[0] = 2;
        primes[1] = 3;
    
        for( int p = 5; p <= MAX_NUM; p += 2)
        {
            isPrime = true;
    
            for( int i = 1; isPrime && primes[i] <= sqrt(p); ++i)
            {
                if(p % primes[i] == 0)
                {
                    isPrime = false;
                    break;
                }
            }
            if( isPrime == true)
            {
                primes[primeIndex ++] = p;
            }
        }
    
        for(int i = 0; i < primeIndex; ++ i)
        {
            printf("%i ", primes[i]);
        }
        printf("
    ");
    }
    

    4. 埃拉托色尼筛网法

    其步骤为:

    1. 定义整数数组P, 将所有的数组元素设置为0.
    2. 设置变量i等于2。
    3. 如果i > n,算法结束。
    4. 如果P[i]等于0, 那么i是一个质数。
    5. 对于所有的正整数j, 如果i * j <= n,将数组元素P[i*j]设置为1。
    6. i的值增加1,返回第3步。

    代码如下:

    void prime_generator_4(void)
    {
        int primes[MAX_NUM + 1] ={0};
        int i = 2;
    
        while(i <= MAX_NUM)
        {
            if(primes[i] == 0)
            {
                printf("%i ", i);
            }
            for( int j = 2; i * j <= MAX_NUM; ++j)
            {
                primes[i * j] = 1;
            }
            ++i;
        }
        printf("
    ");
    }
    

    5. 对比

    MAX_NUM =500000 时,前三种算法的计算时长分别为:

    可以看到,经过改进,算法的时间消耗得到大幅降低,表明改进算法的有效性。

    6. 关于数组越界带来的死循环问题

    这个问题在第4部分代码编写过程中出现过,后来经过搜索找到了原因,数组越界导致循环变量被重新赋值。其汇编代码如下:

    在此验证了一个简单的C语言数组循环语句,对循环变量和数组越界元素的地址进行了输出,可以看到,二者地址一致,证明了以上的论断。

  • 相关阅读:
    第二十篇 sys模块
    第十九章 Python os模块,pathlib 判断文件是目录还是文件
    第三篇 Postman之 Tests(后置处理器,断言)
    第十八篇 模块与包--time&random模块&模块导入import(os.path.dirname(os.path.abspath(__file__)))
    Sublime text3最全快捷键清单
    第十七篇 Python函数之闭包与装饰器
    第二篇 Postman的高阶使用之配置全局变量及局部变量的调用及设置方法(手动方法)
    第六篇 常用请求协议之post put patch 总结
    第十六篇 Python之迭代器与生成器
    PCL—低层次视觉—关键点检测(Harris)
  • 原文地址:https://www.cnblogs.com/mengmz/p/8707313.html
Copyright © 2020-2023  润新知