Scheme中范围集的交集

时间:2014-03-18 04:09:34

标签: scheme racket

我正在尝试编写一个Scheme函数,它将找到包含表示范围的对的集合的交集。

例如,让我们说set1 = ((1 3) (5 13) (25 110) (199 300))

set2 = ((2 4) (17 26) (97 100) (110 200) (288 500))

所以Scheme函数(intersect set1 set2)应该给出结果

((2 3) (25 26) (97 100) (110 110) (199 200) (288 300))

请注意,我并不是要找到集合元素的交集,而是找到集合中对的重叠点。

这是我到目前为止所尝试的

(define (intersect a b)
  (cond
    ((or(null? a)(null? b))(quote ()))
    ((and(>=(cadr(car a))(car(car b)))(>=(cadr(car a))(cadr(car b))))
       (cons(cons (car(car b))(cdr(car b)))
         (intersect (cdr a)(cdr b))))
    ((>=(cadr(car a))(car(car b)))
       (cons(cons (car(car b))(cdr(car a)))
         (intersect (cdr a)(cdr b))))
    ((>=(cadr(car a))(car(car(cdr b))))
       (cons(cons (car(car(cdr b)))(cdr(car a)))
         (intersect (cdr a)(cdr b))))
    ((>=(cadr(car b))(car(car(cdr a))))
       (cons(cons (car(car(cdr a)))(cdr(car b)))
         (intersect (cdr a)(cdr b))))
    (else(intersect (cdr a) (cdr b)))))

但是我输出的结果为((2 3) (25 26) (97 100) (110 200))这是不正确的,因为我应该得到((2 3) (25 26) (97 100) (110 110) (199 200) (288 300))

任何人都有任何建议如何解决我的代码中的错误或错误。

2 个答案:

答案 0 :(得分:1)

;; Function to compute the intersection of two intervals.
;; If the intersection is empty, the function returns #f as the lower limit
;; of the intersection.
(define (intersect-interval a b)

  ;; Assume that (car a) <= (cadr a) and (car b) <= (cadr b)

  ;; Get the lower limit of the intersection.
  ;; If there isn't one, return #f
  (define (lower-limit)
    (if (< (cadr a) (car b))
      #f
      (car b)))

  ;; Get the upper limit of the intersection.
  (define (upper-limit)
    (min (cadr a) (cadr b)))

  ;; Let's make our life simpler.
  ;; Make sure that (car a) is less than (car b)
  ;; for the core computation.

  (if (> (car a) (car b))
    (intersect-interval b a)
    (list
      (lower-limit)
      (upper-limit)))
  )

;; Function that computes the valid intersections of two sets of intervals.
(define (intersect-interval-sets seta setb)

  ;; Helper function that takes one item from the first set and iterates over the
  ;; items of the second set. It computes the intersection of the item from the first set
  ;; and each item of the second set. If there is a valid intesection, it adds it to the output.
  (define (make-intersections-2 item lst2 out)
    (if (null? lst2)
      out
      (begin
        (let ((ints (intersect-interval item (car lst2))))
          (if (eq? #f (car ints))
            (make-intersections-2 item (cdr lst2) out)
            (make-intersections-2 item (cdr lst2) (append out (list ints))))))))

  ;; Helper function that iterates over the items of the first list and calls the previous
  ;; function using each item of the first list and the second list.
  (define (make-intersections-1 lst1 lst2 out)
    (if (null? lst1)
      out
      (make-intersections-1 (cdr lst1) lst2 (make-intersections-2 (car lst1) lst2 out))))

  ;; Start the recursion and return the result.
  (make-intersections-1 seta setb '())
  )

repl.it

进行测试
   (define seta '((2 3) (100 200)))
   (define setb '((5 10) (90 120) (110 300)))
   (intersect-interval-sets seta setb)
=> ((100 120) (110 200))

答案 1 :(得分:1)

如果我们创建一个特殊的辅助函数来查找两个给定区域的交集,生成交叉区域和剩余区域作为结果,这将更容易处理:

(define (intersect xs ys)
  (define (intersect-regions x y)   ; x=(a b) y=(c d), a <= c is assumed NB!
    (let ((b (cadr x)) (c (car y)) (d (cadr y)))  
      (cond
        ( (< b c)            ; 1st region ends before 2nd begins
            (list '()        ; no intersection
                   y))       ; the left-over region
        ( (< b d)            ; thus b >= c, and so, if b < d,
            (list (list c b)      ; b already included: this will
                  (list b d)))    ;  only work for sorted range-lists
        (else                     ; b >= d
            (list y               ; includes d -- will only work for
                  (list d b))))))     ; sorted, 
  (define (loop a b acc)              ;   non-overlapping range-lists
    (if (or (null? a) (null? b))   
      (reverse acc)
      (let ((r (if (<= (caar a) (caar b))
                 (intersect-regions (car a) (car b))
                 (intersect-regions (car b) (car a)))))
          (if (not (null? (car r))) 
             (set! acc (cons (car r) acc)))
          (if (or (null? (cdr a)) (< (cadadr r) (caadr a)))
             (loop (cons (cadr r) (cdr a))  (cdr b)  acc)
             (loop (cdr a)  (cons (cadr r) (cdr b))  acc)))))
  (loop xs ys '()))

函数loop是尾递归的,在累加器参数中构建其结果。我们假设每个范围列表按升序包含非重叠范围。测试:

(intersect '((1 3) (5 13) (25 110) (199 300)) 
           '((2 4) (17 26) (97 100) (110 200) (288 500)))
;Value 18: ((2 3) (25 26) (97 100) (110 110) (199 200) (288 300))