使用遞歸調用來實現快速冪函數可以說是對快速冪函數最為高效的方法之一,一般可以滿足對於算法的時間復雜度需求。(好像還有一種更為高效的實現算法,感興趣的請自行查找)
先貼上代碼:
#include<cstdio> #include<iostream> using namespace std; int Quick_pow(int base,int n) { if(n == 0) return 1; if(n == 1) return base; int res = Quick_pow(base, n>>1); res = res * res; if(n%2 == 1) //n為奇數 if (n & 1) res = res*base; return res; } int main() { int a=Quick_pow(2, 5); cout<< a <<endl; return 0; } /* 1.一般防止數據爆掉,會把base定義為double類型或者是更大 的數據存儲類型,還有一般會把n定義為unsigned int類型,編寫函數時, 應當根據實際需求改變。 2.n>>1表示n對應的二進制的值往右順移一位;if(n%2==1)可以改寫成if(n & 1); 效果等價。不懂怎么用的自行百度。 3.理解代碼的關鍵在於n>>1,打個比方base=5,n=11;各自順移一位如下: (11)1011->(5)0101->(2)0010->(1)0001; 也就是交給遞歸循環的部分永遠會"<="本體的一半,11只給5給子遞歸處理,5只給2; 這樣的話對應代碼的第10行,(5)^5處理完了之后,本體還剩有(5)^6; 然后就是res=res*res;((5)^5*(5)^5,)在之后的工作就簡單了,判斷指數是不是奇數,因為之前5的10次方 已經解決了,如果是奇數的話,那么只需要乘以一遍base就可以return了; */
可能注釋解釋的那么多一下子沒看懂,沒關系,多看幾遍,自己推算一遍就好了,代碼不可多背,要在理解的基礎上再去記憶,這樣才能牢固學到的知識;
接下來是快速冪取模函數:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; ll quickpow(ll m,ll n,ll k) //快速冪取模函數,m:底數:指數,k:取模數 { ll ans=1; //結果數ans
m=m%k; while(n > 0) //當指數大於0的時候就執行循環 { if(n&1) //跟if(n%2 == 1) 的效果一樣 ans = (ans*m)%k; //消除指數為奇數的影響 n=n >> 1; //n的二進制數右移一位; m = (m*m) % k; // 因為指數右移,所以這一步要消除指數右移的影響 } return ans%k; } //其實快速冪取模跟快速冪函數相差無幾,只是記得在關鍵步驟后面要對K取模,防止數據爆掉; int main() { ll n,k,m; while(cin>>m>>n>>k) { cout<< quickpow(m,n,k) <<endl; } return 0; }
多看多學,多讀書 -- 2018/5/4