算法——如何快速判斷素數?

前言

最近閒來無事,刷刷題,碰到這樣一個題目:

需求:要求實現一個判斷素數的簡單函數
相關信息:素數就是隻能被1和自身整除的正整數。注意:1不是素數,2是素數。
輸入:任意整數
輸出:1——素數;0——非素數.

第一反應是將大於等於2的輸入整數循環除以每個小於自身且大於1的整數,若餘數爲0,則爲非素數。
再一想,這樣做速度實在太慢,時間複雜度爲o(n)o(n)。故在網上水了一波,看看到底有沒有更快速的算法。

解決方案

方案1

方案1,就是上述方法,代碼如下:

int prime(int p)
{
	if(p<=1)
	{
		return 0;
	}
	for(int i=2;i<p;i++)
	{
		if(p%i==0)
		{
			return 0;
		}
	}
	return 1;
} 

方案2

方案2是方案1的改進方案,該方案基於以下客觀事實:一個數若可以進行因數分解,那麼分解時得到的兩個數一定是一個小於等於sqrt(n),一個大於等於sqrt(n),據此,上述代碼中並不需要遍歷到n-1,遍歷到sqrt(n)即可,因爲若sqrt(n)左側找不到約數,那麼右側也一定找不到約數。

int prime(int p)
{	
	if(p<=1)
	{
		return 0;
	}
	for(int i=2;i<int(sqrt(p))+1;i++)
	{
		if(p%i==0)
		{
			return 0;
		}	
	}
	return 1;
}

上述算法時間複雜度爲o(sqrt(n))o(sqrt(n)).

方案3(最優算法)

和方案2一樣,首先素數有這樣一個規律:大於等於5的質數一定和6的倍數相鄰。例如5和7,11和13等。
證明過程如下:
x>=1;5...,6x1,6x,6x+1,6x+2,6x+3,6x+4,...66x,2(3x+1),3(2x+1),2(3x+2)6x16x+1; 令x>=1;則大於等於5的自然數表示如下:\\ ...,6x-1,6x,6x+1,6x+2,6x+3,6x+4,... \\ 可以看到,不在6的倍數兩側的數:6x,2(3x+1),3(2x+1),2(3x+2)都不是素數。\\ 可能爲素數的就只有:6x-1和6x+1;
因此,我們將所有輸入的大於等於5的數據以上述方式表示,將其除以6,若餘數不爲1,或者5,則直接證明其不是素數,剩下的進行判斷:

int prime(int p)
{
	if (p == 2 || p == 3)
	{ 
		return 1; 
	}
	if (p % 6 != 1 && p % 6 != 5)
	{ 
		return 0; 
	}
	for (int i = 5; i <= floor(sqrt(p)); i += 6)
	{
		if (p%i == 0 || p % (i + 2) == 0)
		{ 
			return 0;
		}
	}
	return 1;
}

總結

算法3能極大降低運算量,提升運算速度。小小的問題,大大的智慧啊,感謝大神們,雖然我不知道是誰。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章