求兩個數的最大公約數

  • 思路一算法

    從1到兩個數中最小的數遍歷,找到能同時被兩個數都整除的數,並記錄最大的值。編程

    最簡單且效率最低。code

  • 思路二遞歸

    碾轉相除法,古希臘的一位數學家歐幾里得給出的一個高效的算法。他證實了f(x,y)=f(y,x%y)數學

int gcd(int num1,int num2)
{
	return !num2?num1:gcd(num2,num1%num2);
}

很簡單的遞歸,再也不討論class


  • 思路三效率

    從思路二的算法能夠知道,用到了取模運算,也就是用到了除。若是求兩個大數的最大公約數,將是一個很昂貴的開銷,下面介紹第三種思路。書籍

    若是一個數能同時被num1,num2整除,那麼確定能被num1-num2,num2整除,相反,若是一個數能同時被num1-num2,num2整除,那麼確定能同時被num1,num2整除,因此f(num1,num2)=f(num1-num2,num2),這樣就避免了取膜運算。循環

int gcd(int num1,int num2)
{
	//遞歸終止條件,即當num2爲0,num1爲最大公約數
	if(num2==0)
		return num1;
		
	//若是num1<num2,須要調換位置,不然會出現負數
	if(num1<num2)
		return gcd(num2,num1);
	else 
		return gcd(num1-num2,num2);

}

該算法有個缺點,即當兩個相差很大的時候,例如f(10000000000,1),循環次數將大大增長。遍歷

  • 思路四

    該方法結合思路二和思路三的優勢來進行求解。

    若是num1,num2都爲偶數,f(num1,num2)=2f(num1/2,num2/2)

    若是num1爲奇數,num2爲偶數 f(num1,num2)=f(num1,num2/2)

    若是num1爲偶數,num2爲奇數 f(num1,num2)=f(num1/2,num2)

    若是num1爲奇數,num2爲奇數 f(num1,num2)=f(num1-num2,num2)

    又由於除2能夠用>>1來表示,移位操做符的效率是很高的

int gcd(int num1,int num2)
{
	if(num2==0)
		return num1;
	if(num1<num2)
		return gcd(num2,num1);

	if(!num1&0x01)
	{
		if(!num2&0x01)
			return 2*gcd(num1>>1,num2>>1);
		else
			return gcd(num1>>1,num2);
	}
	else
	{
		if(!num2&0x01)
			return gcd(num1,num2>>1);
		else
			return gcd(num1-num2,num2);
	}

}


參考書籍:《編程之美》

相關文章
相關標籤/搜索