比较列表的结构相等性

时间:2013-10-15 21:56:39

标签: list scheme racket equivalence

如何检查Scheme中两个列表的结构相等?例如,(a (b) (c d))等于(a b (c d) (e f g))(a b)等于(a b c)。列表中的 data 内容无关紧要,只有嵌套列表的结构层次结构,即子列表的数量,以及这些子列表的子列表数量等等。

我创建了一个名为eqStruct的函数,它将两个列表作为参数。它应该计算每个列表中的子列表数量ab,然后返回一个布尔值。该函数查看列表a的每个元素,然后查看列表b的每个元素。它使用cd分别作为ab中子列表数量的计数器,当atom?在调用时返回false时,它们会递增列表的元素。在每次查看列表的第一个原子之后,列表被设置为相等而没有第一个项目(list-tail),并且unless循环在整个列表'a和'b已经被终止时终止看着。

(define (eqStruct 'a 'b)

    (define c 0)
    (define d 0)

    (define (atom? x) (not (pair? x)))

    (unless (null? a)
         (unless (atom? (first a)) (set! c (+ c 1))
         (set! a (list-tail a 1))
    )
    (unless (null? b)
         (unless (atom? (first b)) (set! d (+ d 1))
         (set! b (list-tail b 1))
    )

    (eq? c d)
)  

最后一行应该是一个return语句,因为我希望函数是一个谓词,并返回列表是否具有相同的结构,一个布尔值,但我不知道如何实现这一点,或者如果我以正确的方式思考这个问题。

1 个答案:

答案 0 :(得分:4)

您的方法

您的代码(以及您对它的评论)指出了对某些Racket结构的一些误解。

一个大问题是unless不是循环结构;它只是有条件地执行一些代码。例如,如果您评估(unless (= 1 2) (display 'x)),则不会永久打印x,而只需打印一次。这意味着您获得的代码将不会按照您的预期执行。

但是,如果我们假设那是(以便我们了解您的代码尝试做什么),那么您就有了一个合理的想法。您正试图迭代列表a并计算它所包含的元素数量。

    (unless (null? a)
         (unless (atom? (first a)) (set! c (+ c 1))
         (set! a (list-tail a 1))
    )

这是个好主意如果你的列表总是只有一层深。例如,您要正确检查((a b) c)((a) b c),但不会得到((a (b)) c)(具有结构((())()))和(((a) (b)) c)(其中包含((()())())结构a正确。如果您只是想检查bunless是否具有相同数量的列表元素,(如果eq?是循环结构) ,你会走在正确的轨道上。

略有不同(但相似)的方法

您尝试从每个输入列表中提取表示列表结构(在您的情况下是一个数字)并比较这些代表值的一般方法,这是一个很好的方法。我认为你只需要使用稍微不同的代表值,并稍微区别一点(equal?对你的情况很好,我想,但我想到的代表值需要{{1} })。

请注意,考虑到它们的定义方式,可以将结构与equal?进行比较。鉴于这种观察,我认为最简单的方法是编写一个采用列表并返回其规范结构的过程。另请注意,通过在内部list?中使用if,我们可以正确处理((a b) ())等结构为(() ())的案例。

(define (structure list)
  (if (null? list)
      list
      (if (list? (car list))
          (cons (structure (car list)) (structure (cdr list)))
          (structure (cdr list)))))
> (structure '(a (b) (c d)))
(() ())
> (structure '((a b) ()))
(() ())

然后,为了比较两个列表的结构,你可以得到两个列表的结构并进行比较。

(define (structure-equal? list1 list2)
  (equal? (structure list1)
          (structure list2)))
> (structure-equal? '(a b) '(a b c))
#t
> (structure-equal? '(a (b) (c d)) '(a b (c d) (e f g)))
#t

了解equal?对结构起作用的原因不应该太难,但理解 structure的工作方式更为重要。让我们更仔细地看一下

(define (structure list)
  (if (null? list)
      list ; or '()
      (if (list? (car list))                                    
          (cons (structure (car list)) (structure (cdr list)))
          (structure (cdr list)))))

我们假设进来的list实际上是一个列表。这意味着 空列表()(因此(null? list)为真),或者它是具有carcdr的一对。空列表的结构显然是空列表,因此我们可以返回list(因为它是空的)。另一种情况比较复杂; list是一对car具有某种价值且其cdr是其余列表的一对。如果car也是一个列表,那么它会向list的结构添加一些东西,但如果不是,那么它只是一些元素而不会对列表的结构有所贡献。更具体地说,当list(x . y)对时:

  • 如果x是列表,则(x . y)的结构为(<structure of x> . <structure of y>)
  • 如果x不是列表,则(x . y)的结构为<structure of y>

这应该解释内部if内部的逻辑(我们使用(a . b)创建一对(cons a b))。