素数学习

试除法

最简单的想法

对于测试一个正整数 n 是否是素数,最简单的想法就是从 2 开始到 n1 以此测试能否整除 n ,于是有了下面的代码:

<code class="hljs cs has-numbering"><span class="hljs-keyword">bool</span> isPrime(<span class="hljs-keyword">int</span> n)
{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">2</span>; i < n); i++)
    {
        <span class="hljs-keyword">if</span> (!(n % i))
        {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
        }
     }
    <span class="hljs-keyword">return</span> n != <span class="hljs-number">1</span>; <span class="hljs-comment">// 1是例外</span>
}</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

在n比较小的时候,这个算法的运行时间还是能接受的,但当n非常大的时候,这个算法就不能满足要求了,我们需要在此基础上进行优化。

更高级的想法

因为若 d n 的约数,那么 n/d 也是n的约数,也就是说n的约数的最大值为 n (向下取整),那么我们从2遍历到 n 即可,下面是代码:

<code class="hljs cs has-numbering"><span class="hljs-keyword">bool</span> isPrime(<span class="hljs-keyword">int</span> n)
{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">2</span>; i*i <= n); i++) <span class="hljs-comment">// 不能忽略i*i == n的情况</span>
    {
        <span class="hljs-keyword">if</span> (!(n % i))
        {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
        }
     }
    <span class="hljs-keyword">return</span> n != <span class="hljs-number">1</span>; <span class="hljs-comment">// 1是例外</span>
}</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

这个算法的时间复杂度为 Θ(n) ,在多数境况中这已经足够了。

埃拉托斯特尼筛法

如果要打印 n 以内的所有素数,用上面的算法就有点不合适了,埃氏筛法是一个古老的算法,可以在 Θ(nlog(logn)) 的时间复杂度内打印 n 以内的所有素数。

其基本思想是从2开始,将每个素数的各个倍数,标记成合数。一个素数的各个倍数,是一个差为此素数本身的等差数列。由于一个数 n 的最大约数为 n (向下取整),所以从2开始进行到 n (向下取整)即可。

下图是埃拉托斯特尼筛法到的动画演示。
素数学习_第1张图片

代码:

<code class="hljs cs has-numbering"><span class="hljs-keyword">int</span> prime[maxn];
<span class="hljs-keyword">bool</span> is_prime[maxn + <span class="hljs-number">1</span>];

<span class="hljs-keyword">int</span> sieve(<span class="hljs-keyword">int</span> n)
{
    <span class="hljs-keyword">int</span> p = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i <= n; i++)
        is_prime[i] = <span class="hljs-keyword">true</span>;
    is_prime[<span class="hljs-number">0</span>] = is_prime[<span class="hljs-number">1</span>] = <span class="hljs-keyword">false</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">2</span>; i <= n; i++)
    {
        <span class="hljs-keyword">if</span> (is_prime[i])
        {
            prime[p++] = i;
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">2</span> * i; j <= n; j += i)
                is_prime[j] = <span class="hljs-keyword">false</span>;
        }
    }
    <span class="hljs-keyword">return</span> p;
}</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

你可能感兴趣的:(素数学习)