如题:
将如下递归代码改写成非递归形式
int exp(int x, int n) {
if ( n == 0) {
return 1;
} else if (n % 2 == 0) {
return exp (x, n / 2) * exp(x, n / 2);-------------------------(1)
} else {
return x * exp(x,n-1);---------------------(2)
}
}
分析:
- 递归处理式(1),(2)是按n的奇偶性来分别处理的,并且对n为奇数时要进行的下一个子问题中的n = n-1,由n为奇数知,n= n-1必定为偶数,所以(2)执行后的下一步递归式中执行的必定是(1)。
- (1)执行的下一步递归是n = n / 2; 由于n为偶数,所以必定可以整除。然而,由式(1)引发的下一步递归究竟到达(1)(2)中的哪一个就要看n/2的奇偶性了
- 将n表示成二进制数,n为奇数时执行(2)相当于将n末尾的1清掉,接着执行递归(1)得到n>>1的递归参数,再下一步执行(1)还是(2)得看n>>1的末位是否为1了(即n>>1的奇偶性)。
- 具体分析一个实例:n = 7时, 上述递归过程计算x^7可以看成 x*(x*(x)^2)^2, 递归的实际计算过程如下:(x), (x) ^2, x*(x)^2 ,(x*(x)^2)^2, x*(x*(x)^2)^2,递归的调用轨迹可以用(2)(1)(2)(1)(2)然后到"return 1“,一步步退出递归栈了。我们可以发现以上这两个序列和n用二进制表示的莫大关联:7 = 0111B, 0111B 末位为1 因此开始调用递归式(2), 由分析1知,(2)调用后的下一步递归为(1),则011 = (0111-1)/ 2; 再下一步递归式按照011 % 2==1 知应该为(2)。。。。。这样就和(2)(1)(2)(1)(2)相吻合。
- 综上所示,我们完全可以根据n的二进制表示中各位的值(0或者1)来推断递归的轨迹,从而写出上述递归程序的非递归算法:
result = 1;
if( n == 0)
return 1;
tag = 31;
while( (1 << tag) & n ! = 0) tag--;//找到n的二进制表示中最高位所在的位号
while(tag >=0) {
if ((1<<tag) & n !=0) {
result *= x;
result = result * result;
} else {
result = result * result;
}
tag--;
}
return result;