1. 程式人生 > >最大公約數(大數版)

最大公約數(大數版)


示例:

99999999999999999999(20位) 與 6666666666666666666(20位): gcd= 33333333333333333333(20位)

思路:全部寫在註釋裡面了~

/***********************************************************
	FileName: 大數最大公約數(位移版).cpp
	Author: Dojking
	Version : V1.0          
	Date:2014/3/16
	Function List:   
				1.int main()                  主函式
				2.void strmod();              模擬大數取餘
				3.void strsub();              模擬大數減法
	History:       
		<author>  <time>   <version >   <desc>
		Dojking   2014/3/16   1.0		build  
***********************************************************/

#include <iostream>
#include <string>
using namespace std;

int pos, zero, len1, len2;/*pos:匹配位置,zero:str1高位最後一個0的位置,len1:str1長度,len2:str2長度*/
string str1, str2, mod;   /*str1:大數1,str2:大數2,mod:每步的餘數*/

/********************************************************************************************************
	strsub()函式:
	模擬大數快速減法,末尾補0法雖然能快速的做減法,然後由於是字串操作,末尾減0的操作實際上是無用的操作。
	這裡引入位移法,進行快速減法。
	具體思想:(假設str1 > str2)我們先比較str1[0],str2[0]值得大小,用以確定str2與str1的匹配位置。
	比如:str1=12345678 , str2=431,由於str1[0] < str2[0],所以應當這樣匹配做減法:
	str1:   12345678                 
	str2:    431
	又如:str1=5173 , str2=29,由於str1[0] > str2[0],所以應當這樣匹配做減法:
	str1:   5173
	str2:   29
	同時,直接在str1裡面儲存減好的值。並且用str2的長度控制減法的次數。
********************************************************************************************************/
void strsub()             /*該函式用大數減法,模擬取餘*/
{
	int i,j;

	pos = zero+1;         /*pos指向str1有效位的第一位*/
	if (str1[pos] < str2[0])/*如果str1[pos] < str2[0],說明不能從最高位開始減。如123 - 45也不能從最高位開始減*/
	{
		++pos;            /*後移一位*/
	}

	for (i=pos+len2-1,j=len2-1; j >= 0; --i,--j) /*模擬減法*/
	{
		if (str1[i] < str2[j] || str1[i] == 'f') /*需要借位,f表示-1*/
		{
			if (str1[i-1] != '0')                /*高位不為0*/
			{
				str1[i-1] -= 1;                  /*向高位借位*/
			} 
			else                                 /*高位為0,借位後變為-1,用f表示-1*/
			{
				str1[i-1] = 'f';                 /* f = -1 */
			}
			if (str1[i] == 'f')                  /*本位為f,直接用-1代替*/
				str1[i] = ((-1+10)-(str2[j]-'0')+'0');
			else                                 /*本位不為f,執行 '-' 操作*/
				str1[i] = ((str1[i]-'0')+10-(str2[j]-'0')+'0');
				
		}
		else         /*不需要借位,直接 '-' 操作*/
		{
			str1[i] = ((str1[i]-'0')-(str2[j]-'0')+'0');
		}
	}
	while (str1[zero+1] == '0' && (len1-zero) != 2)  /*去掉相減後高位上的無效0。(len1-zero) != 2:防止全為0的情況)*/
	{
		++zero;
	}
}

/****************************************************************************
	strmod()函式:
	主要負責一些值的初始化,捨去str1高位上的無效0,和當str1 < str2時跳出迴圈。
****************************************************************************/
void strmod()    /*此函式作用相當於 str1 %= str2,注意str1,str2都是全域性變數*/
{
	zero = -1;   /*zero指向當前高位上最後一個0的位置*/
	len1 = str1.size(); /*獲得串長度*/
	len2 = str2.size();
	/*如果str1 < str2,則跳出。注意字串模擬數字大小比較,同時str1前面可能有多餘的0*/
	while (! (len1 - (zero+1) < len2 || str1[zero+1] < str2[0] && (len1 - (zero + 1) <= len2)) )
	{
		strsub();       /*進行大數減法,模擬取餘*/
	}
	mod = "";           /*重置mod,避免對下面的mod+=造成影響*/
	while (zero < len1-1) /*捨去str1高位上的0,將有效數字拷貝進mod,傳進main函式,進行下次輾轉*/
	{
		mod += str1[++zero];
	}
}

/****************************************************************************************
	main()函式:
	主函式,函式中省去了,swap()函式,因為不管是str1>str2,還是str1<str2都不影響執行結果。
	分析:如果str1 < str2。程式執行到strmod()中將不進入while(1),然後返回main()函式。
	在main()-while()中交換了str1,str2的值。
	同時,主函式中增加了一個迴圈函式,便於測試多組資料,而不是執行一次只能測試一組資料。
****************************************************************************************/
int main()
{
	while (1)     /*便於測試多組資料*/                
	{
		cin>>str1>>str2;                        /*輸入兩個大數*/
		if (str1[0] == '0' || str2[0] == '0')   /*請不要輸入0*/
		{
			cout<<"input error"<<endl;
			break;
		}
		while (str2[0] != '0')   /*大數取餘運算跳出條件*/
		{
			strmod();            /*此函式作用相當於 str1 %= str2,注意str1,str2都是全域性變數*/
			str1 = str2;         /*str1儲存較大數*/
			str2 = mod;          /*str2儲存餘數*/
		}
		cout<<str1<<endl;        /*輸出求餘結果*/
	}

	return 0;
}