1. three rules for solving problem recursively --- take every recursive problem as if it were a journey
1) Know when to stop;
2) Decide how to take one step;
3) Break the journey down into that step plus a smaller journey.
2. 递归模式
1)双测试尾递归
(defun func (x)
(cond (end-test-1 end-value-1)
(end-test-2 end-value-2)
(t (func reduced-x))))
ex
(defun anyoddp (x)
(cond ((null x) nil)
((oddp (first x)) t)
(t (anyoddp (rest x)))))
2)单测试尾递归
(defun func (x)
(cond (end-test end-value)
(t (func reduced-x))))
ex
(defun find-first-atom (x)
(cond ((atom x) x)
(t (find-first-atom (first x)))))
3)单测试增量递归
(defun func (x)
(cond (end-test end-value)
(t (aug-fun aug-val
(func reduced-x)))))
ex
(defun count-slices (x)
(cond ((null x) 0)
(t (+ 1 (count-slices (rest x))))))
3)列表构造递归
(defun func (n)
(cond (end-test nil)
(t (cons new-element
(func reduced-n)))))
ex
(defun laugh (n)
(cond ((zerop n) nil)
(t (cons 'ha (laugh (- n 1))))))
4)多变量递归
(defun func (n x)
(cond (end-test end-value)
(t (func reduced-n reduced-x))))
ex
(defun my-nth (n x)
(cond ((zero p) (first x))
(t (my-nth (- n 1) (rest x)))))
5)条件增量
(defun func (x)
(cond (end-test end-value)
(aug-test (aug-fun aug-val
(func reduced-x))
(t (func reduced-x))))
ex
(defun extract-symbols (x)
(cond ((null x) nil)
((symbolp (first x))
(cons (first x)
(extract-symbols (rest x))))
(t (extract-symbols (rest x)))))
6)多重递归
(defun func (n)
(cond (end-test-1 end-value-1)
(end-test-2 end-value-2)
(t (combiner (func first-reduced-n)
(func second-reduced-n)))))
(defun fib (n)
(cond ((equal n 0) 1)
((equal n 1) 1)
(t (+ (fib (- n 1))
(fib (- n 2))))))
7)CAR/CDR 递归
(defun func (x)
(cond (end-test-1 end-value-1)
(end-test-2 end-value-2)
(t (combiner (func (car x))
(func (cdr x))))))
(defun find-number (x)
(cond ((numberp x) x)
((atom x) nil)
(t (or (find-number (car x))
(find-number (cdr x))))))
8) 尾递归
尾递归技术
尾递归技术可以消除递归调用之间的“依赖性”,使得空间复杂度为O(1)
尾递归四大特征:
(1)绝大多数尾递归为“主函数+helper”形式,通过帮助函数实现递归主体;
(2)使用额外的变量在递归调用之间传递计算的中间结果;
(3)递归分支是纯的,不包含其他运算;
(4)非递归分支返回的是中间计算的结果;
Keyboard Exercise
Keyboard Exercise
(defparameter *family*
'((colin nil nil)
(deirdre nil nil)
(arthur nil nil)
(kate nil nil)
(frank nil nil)
(linda nil nil)
(suzanne colin deirdre)
(bruce arthur kate)
(charles arthur kate)
(david arthur kate)
(ellen arthur kate)
(george frank linda)
(hillary frank linda)
(andre nil nil)
(tamara bruce suzanne)
(vincent bruce suzanne)
(wanda nil nil)
(ivan george ellen)
(julie george ellen)
(marie george ellen)
(nigel andre hillary)
(frederick nil tamara)
(zelda vincent wanda)
(joshua ivan wanda)
(quentin nil nil)
(robert quentin julie)
(olivia nigel marie)
(peter nigel marie)
(erica nil nil)
(yvette robert zelda)
(diane peter erica)))
(defun father (person)
(second (assoc person *family*)))
(defun mother (person)
(third (assoc person *family*)))
(defun parents (person)
(append (and (father person) (list (father person)))
(and (mother person) (list (mother person)))))
(defun children (person)
(and person
(mapcar #'first
(remove-if-not #'(lambda (rec)
(or (equal person (second rec))
(equal person (third rec))))
*family*))))
(defun siblings (person)
(set-difference
(union (children (father person))
(children (mother person)))
(list person)))
(defun mapunion (func lst)
(apply #'union (mapcar func lst)))
(defun grandparents (person)
(mapunion #'parents (parents person)))
(defun cousins (person)
(mapunion #'children
(mapunion #'siblings (parents person))))
(defun descended-from (x y)
(cond ((null x) nil)
((member y (parents x)) t)
(t (or (descended-from (father x) y)
(descended-from (mother x) y)))))
(defun ancestors (person)
(cond ((null person) nil)
(t (append (parents person)
(ancestors (father person))
(ancestors (mother person))))))
(defun g-gap-helper (p1 p2 n)
(cond ((null p1) nil)
((equal p1 p2) n)
(t (or (g-gap-helper (father p1) p2 (1+ n))
(g-gap-helper (mother p1) p2 (1+ n))))))
(defun generation-gap (p1 p2)
(g-gap-helper p1 p2 0))