1. 程式人生 > >【演算法】3.Eratosthenes篩選法與尤拉篩選法求素數

【演算法】3.Eratosthenes篩選法與尤拉篩選法求素數

Eratosthenes篩法

1.原理

一個合數可以分成幾個素數的和,如果把素數(最初只知道2)的倍數全都去掉,剩下的就都是素數了

2.思路分析
  1. 去除0,1(既不是素數又不是合數)
  2. 找到佇列中最小的素數,刪除其倍數

在這裡插入圖片描述

3.程式碼實現(只給出了函式,未寫主函式)

用一陣列存這一列數,陣列的標號即為數字,值1表示為素數,值0表示不為素數

void sieveofe(int p[], int n)   //將陣列p[],和陣列的最大範圍n,輸入
{
    int i, j;
 
    p[0] = 0;
    p[1] = 0;
    p[2
] = 1; // 初始化 for(i = 3; i <= n; i++) { p[i++] = 1; p[i] = 0; } //除了2,其餘偶數都是合數,先去除偶數 int max = sqrt(n); for(i = 3; i <= max; i++) //只需要判斷到sqrt(n) { if(p[i]) { for(j = i * i; j < n; j += i) p[j] = 0; //進行篩選,從i*i開始,如對素數3,從3*3開始,不需要從3*2開始,因為對素數2,2*3已經篩去
} } }

尤拉篩法

Eratosthenes篩選法雖然效率高,但是Eratosthenes篩選法做了許多無用功,一個數會被篩到好幾次, 2✖6和3✖4都將12篩去,最後的時間複雜度是O(nloglogn),對於普通素數演算法而言已經非常高效了,但尤拉篩選法的時間複雜度僅僅為O(n).

1.原理:

只需要依次篩去由素數為因子的數,剩下的都為素數
prime[ ] 陣列中的素數是遞增的,當 i 能整除 prime[ j ] ,那麼 i*prime[ j+1 ] 這個合數肯定被 prime[ j ] 乘以某個數篩掉。因為i中含有prime[ j ]。接下去的素數同理。所以不用篩下去了。

在滿足i%prime[ j ] == 0這個條件之前以及第一次滿足改條件時, prime[ j ] 必定是 prime[ j ]*i 的最小因子。

2.程式碼實現:
const int Max = 100002;        
int Prime[Max];            //用於存素數的值
int vis[Max];              //用於判斷並存所有的素數
void prime()
{
    int num = 0;
    memset(vis,1,sizeof(vis));    //申請空間,將vis陣列都賦初值1,即都為素數 
    for(int i = 2; i <= Max; i++)
    {
        if(vis[i])
            Prime[num++] = i;     //依次存最小的素數
        for(int j = 0; j < num; j++)
        {
            if (i * Prime[j] > Max)
                break;
            vis[i * Prime[j]] = 0; //即 i*Prime[j]也不為素數
            if (i % Prime[j] == 0)
                break;
        }
    }
}

總結:

  1. Eratosthenes篩法的第一重迴圈是用來找素數,然後把素數的倍數標記,而尤拉篩法換了一個角度,第一位是找素數,但是標記的時候用的是所有數
  2. 尤拉篩選法在資料小的時候不如Eratosthenes篩選法快,反而是資料變大以後,兩者差距變得越來越明顯,尤拉篩選法明顯快於Eratosthenes篩選法
  3. 尤拉演算法是一種空間換時間的演算法
參考文章:

https://blog.csdn.net/u012102306/article/details/71407105
https://blog.csdn.net/u012313335/article/details/47663801