我在寻找一种递归计算面积的方法时遇到了问题。
(check-expect(signed-area(list (make-posn 1 2)(make-posn 3 4)(make-posn 5 6)(make-posn 1 6)))8)
(check-expect(签名区域(列表(make-posn 1 2)(make-posn 11 3)(make-posn 12 9)(make-posn 2 10)))70)
(define (signed-area lop)
(cond
[(< 3 (length lop)) 0]
[else
(abs (/ (+(-(* (posn-x (first lop)) (posn-y (second lop)))
(* (posn-x(second lop)) (posn-y(first lop))))
(-(* (posn-x (second lop)) (posn-y (third lop)))
(* (posn-x(third lop)) (posn-y(second lop))))
(-(* (posn-x (third lop)) (posn-y (fourth lop)))
(* (posn-x(fourth lop)) (posn-y(third lop))))
(-(* (posn-x (fourth lop)) (posn-y (first lop)))
(* (posn-x(first lop)) (posn-y(fourth lop)))))
2))]))
我不知道如何递归浏览列表,并删除列表中的第一个posn。由于我的代码限制为4分,因此我必须至少设置3分
答案 0 :(得分:2)
解决方案一-直接递归
但是,问题出在整个公式的最后是absolute
函数。
为了最终在全部金额上执行此操作,您必须将函数放入外部函数,并在函数调用上应用abs
:
(define (signed-area plist)
(define (.signed-area plist)
(cond ((< (length plist) 3) 0)
(else (+
(/ (- (* (first plist) (fourth plist))
(* (second plist) (third plist)))
2)
(.signed-area (cddr plist))))))
(abs (.signed-area plist))) ;; final absolute
您也可以在除以 完全绝对总和因此,效率至少非常低-但实际上改进几乎可以忽略。
(define (signed-area plist)
(define (.signed-area plist)
(cond ((< (length plist) 3) 0)
(else (+
(- (* (first plist) (fourth plist))
(* (second plist) (third plist)))
(.signed-area (cddr plist))))))
(* (/ 1 2) (abs (.signed-area plist))))
解决方案II-尾调用递归
这是一种节省内存的技术,可避免为解释器嵌套递归调用。因此通常被视为最佳做法。
此外,您可以更清楚地看到步骤之间发生了什么-
您只需要专注于acc
以及在每个递归步骤上要执行的操作-然后您就可以了解对每个步骤的结果所采用的公式/过程。由于这两个原因,尾调用递归是Lisp程序员构造递归函数的首选方法。
(define (signed-area plist)
(define (.signed-area plist acc) ; introduce accumulator
(cond ((< (length plist) 3) (* (/ 1 2) (abs acc)))
(else (.signed-area (cddr plist) ; in next round remove first pair
(+ (- (* (first plist) (fourth plist))
(* (second plist) (third plist)))
acc))))) ; add shoelace product to accumulator
(.signed-area plist 0)) ; call inner recursive function with accumulator start value 0
;
测试
所有三个函数定义给出正确的结果2
:
(signed-area (list 1 2 3 4 5 6))
;; => 2
要进行检查/测试,请手动计算示例:
;; to check, calculate shoelace by hand:
;; visualize:
;; 1 2
;; 3 4
;; 5 6
;
;; and then calculate:
(* (/ 1 2)
(abs (+ (- (* 1 4)
(* 2 3))
(- (* 3 6)
(* 4 5)))))
;; => 2
有关排名列表
(define (signed-area list-of-posn)
(define (.signed-area list-of-posn acc) ; introduce accumulator
(cond ((< (length list-of-posn) 2) (* (/ 1 2) (abs acc)))
(else (.signed-area (cdr list-of-posn) ; in next round remove first posn
(+ (- (* (posn-x (first list-of-posn)) (posn-y (second list-of-posn)))
(* (posn-x (second list-of-posn)) (posn-y (first list-of-posn))))
acc))))) ; add shoelace product to accumulator
(.signed-area list-of-posn 0)) ; call inner recursive function with accumulator start value 0