递归子列表?功能

时间:2015-02-27 23:59:02

标签: scheme

我似乎无法想象如何编写正确的uscheme(MIT Scheme的衍生物)函数,它将返回布尔值,无论列表是否包含较小的列表。

我写了这个。

(define sublist? (xs ys)
    (if (= xs '())
        #t
        (if (= ys '())
            #f
            (if (= (car xs) (car ys))
                (sublist? (cdr xs) (cdr ys))
                (sublist? xs (cdr ys))
            )
        )
    )
)

除了这一个测试用例外,它通过了我的大部分测试用例。

(sublist? '(a b c) '(1 2 a 3 b 4 c 5 6))
;; this returns true while it's supposed to return false

测试用例要求子列表是连续的,中间没有随机元素。

我有点担心如何纠正这个问题。有没有其他人有想法?

3 个答案:

答案 0 :(得分:1)

问题是你的算法过于急切 - 一旦找到两个相等的元素,它会立即丢弃该元素并继续检查。实际上,找到两个相等的元素是不够的,因为如果找到不完整的匹配,你的算法可能不得不回溯。

表示此类算法的最简单方法是使用辅助函数来确定子列表是否与列表中的给定位置匹配。然后,sublist?函数将遍历较大列表中的每个位置以查找匹配项。

这是我的实施:

(define (sublist? xs ys)
  (define (sublist-equal? xs ys)
    (cond
      ((null? xs) #t)
      ((null? ys) #f)
      ((equal? (car xs) (car ys))
       (sublist-equal? (cdr xs) (cdr ys)))
      (else #f)))
  (cond
    ((null? xs) #t)
    ((null? ys) #f)
    ((sublist-equal? xs ys) #t)
    (else (sublist? xs (cdr ys)))))

请注意内部sublist-equal?辅助函数。

我还使用cond而不是嵌套的if表达式,因为在这种情况下应该真正使用cond来表示这种逻辑。此外,我使用equal?代替=,因为我知道的大多数方案,=用于数字比较(您可能会有所不同,我不知道)。

答案 1 :(得分:1)

这是我的版本"没有辅助功能"。但它确实使用了两个嵌套循环:

(define (sublist? needle haystack)
  (if (null? needle)
      #t
      (let ((first (car needle)))
        (let outer ((cur haystack))
          (define (next)
            (outer (cdr cur)))
          (cond ((null? cur) #f)
                ((eqv? (car cur) first)
                 (let inner ((lhs (cdr needle))
                             (rhs (cdr cur)))
                   (cond ((null? lhs) #t)
                         ((null? rhs) (next))
                         ((eqv? (car lhs) (car rhs))
                          (inner (cdr lhs) (cdr rhs)))
                         (else (next)))))
                (else (next)))))))

答案 2 :(得分:0)

(define sublist? (xs ys)
  (cond ((= xs '()) #t)  ;;cond easier to read than 
        ((= ys '()) #f)  ;;nested if statements
        ((and (= (car xs) (car ys)) 
 ;;need to check for more than singleton match
              (or (null? (cdr xs))
                  (and (not (null? (cdr ys)))
                       (= (cadr xs) (cadr ys))
                       (sublist? (cdr xs) (cdr ys)))))) ;not tail call
  ;;this cond clause has no second part, 
  ;;the first will return #t or #f
  ;;will backtrack if #f is propagated up the stack.
         (else (sublist? xs (cdr ys)))) ; tail call