最近在看侯捷的《STL源码剖析》,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下。
6章--power算法分析
书本中的算法如下所示:
template <class _Tp, class _Integer, class _MonoidOperation>
_Tp __power(_Tp __x, _Integer __n, _MonoidOperation __opr)
{
if (__n == 0)
return identity_element(__opr);
else {
while ((__n & 1) == 0) {
__n >>= 1;
__x = __opr(__x, __x);
}
_Tp __result = __x;
__n >>= 1;
while (__n != 0) {
__x = __opr(__x, __x);
if ((__n & 1) != 0)
__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>());
}
此处的幂运算X^N,采用的思路是将十进制N化解为二进制,N=(2^0)*N0+(2^1)*N1+……,其中Ni为化为二进制时第i位(0或1)。
如:N=40,化为二进制时为101000,此时X^40 =X^[ (2^0)*0 +(2^1)*0+(2^2)*0+(2^3)*1+(2^4)*0+(2^5)*1]
可以化简为X^[(2^3)*1+(2^5)*1 ] = [X^(2^3)]*[X^(2^5)] ,X^[(2^i)*Ni] 后一项X^ {[2^ (i+1)] * Ni+1 },若Ni+1与Ni都为1,则前式后一项为前一项自己的平方。
幂运算用乘法来做,用移位运算和乘法运算来实现。
程序的思路:
(1)特殊情况,若N==0,则返回自己,与数学中X^0=1不相同。
(2)非特殊情况,
首先找到N化为2进制时最低位为1的那位,代码如第一个while循环,每次检测最低位是否为1,再进行右移判断,
如N化为二进制为101000,退出while时,N=101,x = X^(2^3),从此处可以看出x相同于数制的位权。(程序中的中间值x这里我用小x表示,初值用X表示);
然后对N去掉后面零的值逐位判断,每次都增大x,得到位权,如果为1,则与result相乘,直到N==0。
我们都知道,stl中的算法几乎总是最高效的,思考一下为什么不用N个数相乘呢?如果用N个数相乘O(N),而用此二分法则是O(logN),且从前面非0的位开始,提高了效率。
同时感觉进制转换算法与此类似。