查找列表中两点之间的最大距离(方案)

时间:2013-10-23 06:28:01

标签: scheme distance

我正在尝试从一个点列表中编写一个函数,该点列表返回从点p到距离p最远的点列表中的点的距离。我的要点如下:

((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1))

我还做了一些抽象来检索通用汽车和cdr(为了更容易在代码中查看),以及列表本身的汽车和cdr。

(define (get-x p) (car p)
(define (get-y p) (car p)


(define (get-first-point pt-list)
        (get-x pt-list))

(define (get-rest-points pt-list)
        (get-y pt-list))                                                                                         

我已经写出了一个广义距离公式,我可以用于我选择的任何两点(请记住,我将汽车和cdr抽象为get-x和get-y)。

(define (distance a b)
    (if (or (null? a) (null? b))
        0
        (sqrt (+ (expt (- (get-x a)
                          (get-x b))  2) 
                 (expt (- (get-y a) 
                          (get-y b))  2)))))

现在我有了这个,我知道我需要比较整个点集中的各种距离并选择最大返回值。我有一个部分解决方案,但没有一个对每个点都是正确的。

(define (max-distance p pt-list)
    (if (null? pt-list)
        0
        (max (distance p (get-first-point pt-list)) ; 1
             (distance p (get-first-point (get-rest-points pt-list))) ; 2
             (distance p (get-first-point (get-rest-points (get-rest-points pt-list)))) ; 3
             (distance p (get-first-point (get-rest-points (get-rest-points (get-rest-points pt-list))))) ; 4
             (distance p (get-first-point (get-rest-points (get-rest-points (get-rest-points (get-rest-points pt-list)))))) ; 5
             (distance p (get-first-point (get-rest-points (get-rest-points (get-rest-points (get-rest-points (get-rest-points pt-list))))))) ; 6
    )
)

你可能会得到我(可怕)尝试做的事情的要点,但这就是我需要帮助的原因。

3 个答案:

答案 0 :(得分:3)

在这种情况下,您希望在点列表中fold有一个 f 函数。函数 f 应该距离 d 并指向 x 并返回最大 d 之间的距离> x 和您的特殊指定点 p 。我在其他一些答案中更详细地描述了折叠:

重点是,在折叠中,您可以获取函数,初始值和列表。您将函数应用于列表的第一个元素和初始值以生成一些新值。现在,您使用相同的函数,新值和列表的其余部分递归折叠。这基本上是这样的循环:

  

当前值 = 初始值
   列表不为空   当前值 =使用 list 的第一个元素和当前值调用的函数结果
   list = 列表的其余部分
  返回 当前值

在Scheme中,尾部调用优化得到保证, 该循环。在您的情况下,您只需要确定初始值应该是什么,以及函数应该是什么。由于距离总是非负的,因此合理的初始值为零。功能有点复杂。 当前值将是一个距离,但 list 的第一个元素将是一个点。函数的结果需要是一个新的距离,新的距离应该是距离当前值的最大距离以及 list 中某些点与之间的距离特别的一点。在Racket中,这种折叠被称为foldl,所以我们最终会得到这样的结果:

(define special-points '((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1)))

(define (distance a b)
  (let ((square (lambda (x)
                  (* x x))))
    (sqrt (+ (square (- (car a) (car b)))
             (square (- (cdr a) (cdr b)))))))

(define (max-distance point points)
  (foldl (lambda (current-point current-distance)
           (max current-distance
                (distance point current-point)))
         0
         points))
> (max-distance '(4 . 12) special-points)
13.601470508735444
> (max-distance '(8 . 8) special-points)
13.0
> (max-distance '(2 . 5) special-points)
7.615773105863909

如果您不使用Racket,则必须编写自己的foldl,但实际上并不是很难。 (这实际上并不像Racket的foldl那么复杂,它可以采用任何正数的列表,但它适用于这种情况。)

(define (foldl function initial-value list)
  (if (null? list)
      initial-value
      (foldl function
             (function (car list) initial-value)
             (cdr list))))

答案 1 :(得分:1)

get-y应该使用cdr,而不是car

get-xget-y错过了右括号。

对于max-distance,我会选择

(define (max-distance p pt-list)
  (apply max (map (lambda (x) (distance p x)) pt-list)))

表示您不需要get-first-pointget-rest-points

插图(使用(1.1)作为p):

> (map (lambda (x) (distance '(1 . 1) x)) '((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1)))
'(3.1622776601683795 5.385164807134504 11.704699910719626 5.385164807134504 10.897706180660222 2.23606797749979)

> (apply max (map (lambda (x) (distance '(1 . 1) x)) '((2 . 4) (3 . 6) (5 . 12) (-4 . 3) (8.4 . 9) (0 . -1))))
11.704699910719626

根据您对“最远”的定义,您可能希望在表达式中包含abs

答案 2 :(得分:1)

计算car points的距离。该距离是cdr points的最大值或最大值。结果是一个简单的递归算法遍历点列表。

(define (max-distance-p p points)
  (if (null? points)
      0
      (max (distance p (car points))
           (max-distance-p p (cdr points)))))

如果您将0作为空列表传递,则会返回points;这可能有点可疑。如果是这样的话:

(define (max-distance-p p points)
  (assert (not (null? points)))
  (if (null? (cdr points))
      (distance p (car points))
      (max (distance p (car points))
           (max-distance-p p (cdr points)))))