球拍中的鞋带配方

时间:2018-11-04 00:49:25

标签: list recursion position racket

enter image description here

我在寻找一种递归计算面积的方法时遇到了问题。

(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分

1 个答案:

答案 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