近来学习STL,看到power函数的实现感觉挺有趣,记录一下。
1. 一般情况下,我自己要实现乘幂函数会这样实现:
int power(int x,size_t n) { int result = 1; while (n--) result *= x; return result; }
这样即使实现,这里的时间复杂度和n有关,时间复杂度为0(n)。
2. 看了stl源码实现是这样:
// Returns __x ** __n, where __n >= 0. _Note that "multiplication" // is required to be associative, but not necessarily commutative. //意思是multiplication要满足结合律,但不需要满足交换律 template <class _Tp, class _Integer, class _MonoidOperation> _Tp __power(_Tp __x, _Integer __n, _MonoidOperation __opr) //这里第三个参数是一个二元操作函数 { if (__n == 0) return identity_element(__opr); //返回1 else { while ((__n & 1) == 0) //如果n为偶数 { __n >>= 1; __x = __opr(__x, __x); } _Tp __result = __x; __n >>= 1; while (__n != 0) { __x = __opr(__x, __x); if ((__n & 1) != 0) //如果n为奇数 __result = __opr(__result, __x); __n >>= 1; } return __result; } } template <class _Tp, class _Integer> inline _Tp __power(_Tp __x, _Integer __n) { return __power(__x, __n, multiplies<_Tp>()); } // Alias for the internal name __power. Note that power is an extension, // not part of the C++ standard. template <class _Tp, class _Integer, class _MonoidOperation> inline _Tp power(_Tp __x, _Integer __n, _MonoidOperation __opr) //也可以自定义,传进去一个函数 { return __power(__x, __n, __opr); } template <class _Tp, class _Integer> inline _Tp power(_Tp __x, _Integer __n) //默认情况下是乘幂 { return __power(__x, __n); }
这里:当n为偶数时,X^n=(X^2)^(2/n),此时看2/n是否还是偶数,如果是则继续,否则,转向n是奇数的情况;
当n为奇数时,X^n=X*X^(n-1);
例如计算5^6=(5^2)^3,也就是计算25^3。
这种情况和第三种情况类似,只是当n开始为偶数时,比第三种方法的效率更高,n为奇数时,和第三种方法时间复杂度一样。
3. 第三种实现,和stl源码差不多,只是表示更简洁,和第二种情况相比效率会差点:
int power(int x, size_t n) { if(n == 0) return 1; int result = 1; while(n) { if(n & 1) //n为奇数时 result *= x; n >>= 1; x *= x; }
return result; }
如计算5^6是6化为二进制为0110,所以这里5^6=5^2*5^4,这里时间复杂度为0((log2n)+1)