通常,求bn可以利用下面的递归方式:
bn = b*bn-1
b0 = 1
代码如下:
;normal Recursive
(define (expt b n)
(if (= n 0)
1
(* b (expt b (- n 1)))))
这种递归空间复杂度是n,可以改进为迭代方式:
;normal Iterative
(define (expt2 b n)
(define (expt-iter b counter product)
(if (= counter 0)
product
(expt-iter b (- counter 1) (* b product)))))
(expt-iter b n 1)
现在的空间复杂度就变为了1.
如果采用连乘的方式:
n为偶数:bn = (bn/2)2
n为奇数:bn = b*bn-1
就可以用下面代码描述了:
;continue mul Recursive
(define (expt3 b n)
(cond ((= 0 n) 1)
((even? n) (square (expt3 b (/ n 2))))
(else (* b (expt3 b (- n 1))))))
;判断是否为偶数
(define (even? n)
(= (remainder n 2) 0))
这种过程只需要logn 加上 n的二进制表示中1的个数 减去 1 次即可计算完成。时间复杂度又下降很多。
然而空间复杂度(logn)还是可以改进。
那就是采用连乘的迭代计算过程,下面代码描述了该过程:
;continue mul Iterative
(define (fast1 b n)
(define (fast-expt a b n)
(cond ((= 0 n) a)
((and (= 1 n) (= 1 a)) b)
((= 1 n) a)
((even? n) (fast-expt (* a b b) b (/ n 2)))
(else (fast-expt (* a b b b) b (/ (- n 1) 2) ))))
(fast-expt 1 b n))
;continue mul Iterative
;the next answer found at http://community.schemewiki.org/?sicp-ex-1.16
(define (fast2 b n)
(define (iter a b n)
(cond ((= n 0) a)
((even? n) (iter a (square b) (/ n 2)))
(else (iter (* a b) b (- n 1)))))
(iter 1 b n))
(define (square x) (* x x))
第二种方式是在网上找到的,比较巧妙,在改变状态的同时,改变基数来满足乘积不变。
一般说,定义一个不变量,要求他在状态之间保持不变,这一技术是思考迭代算法设计问题时的一个重要方法。
在已经提供的参数(这里是指数n和基数b)之外,如何确定一个附加的状态变量a,在状态变化时,保持不变量(用状态变量a,和已经提供的参数表示,在这里值就是b^n)。