【问题标题】:Function to check equality between trees检查树之间是否相等的函数
【发布时间】:2012-11-20 03:42:51
【问题描述】:

如何在 Scheme 中实现一个相等函数,它需要两棵树并检查它们是否具有相同的元素和结构?

【问题讨论】:

  • 让我们考虑一下。如果我们有两棵树,每棵树都有一个元素,我们如何判断它们是否相等?
  • 长度相等(因为它们由列表表示),或者用“eq?”也许?
  • 您仍在尝试直接跳到整个问题的解决方案。这不是解决问题的正确方法——你想解决可能的最小问题,然后从中建立一个更大的解决方案。所以,如果我们有一棵 one element 的树(它只包含根节点),并且我们有另一棵 one element 的树,我们如何检查它们是否是一样吗?
  • 相关:tree-equal? in Scheme。该问题有一个特定的编程错误,但接受的答案(免责声明:这是我的)确实包含此问题的答案。

标签: tree scheme equality


【解决方案1】:

从每棵树的根递归
如果根值相似 - 继续左子树,然后是右子树
任何区别 - 打破

【讨论】:

    【解决方案2】:

    我们可以使用 equal?

     (equal? '(a (b (c))) '(a (b (c))))
    

    但是,为了好玩,继 Vassermans 提到“中断”之后,这可能是利用 Schemes 延续控制能力的好机会!

    如果我们发现树有任何差异,我们可以使用 call/cc 提前发出回报。这样我们就可以直接跳回到调用者的延续,而不必展开堆栈。

    这是一个非常简单的例子。它假设树是格式良好的,并且只包含作为叶子的符号,但它应该有希望展示这个概念。您会看到该过程明确接受延续作为参数。

     (define (same? a b return)
       (cond
         ((and (symbol? a) (symbol? b))      ; Both Symbols. Make sure they are the same.
           (if (not (eq? a b))
             (return #f)))
         ((and (empty? a) (empty? b)))       ; Both are empty, so far so good.
         ((not (eq? (empty? a) (empty? b)))  ; One tree is empty, must be different!
           (return #f))
         (else
           (begin
             (same? (car a) (car b) return)  ; Lets keep on looking.
             (same? (cdr a) (cdr b) return)))))
    

    call/cc 让我们捕获当前的延续。这是我如何调用这个过程:

     (call/cc (lambda (k) (same? '(a (b)) '(a (b)) k)))                      ; --> #t
     (call/cc (lambda (k) (same? '(a (b (c) (d e))) '(a (b (c) (d e))) k)))  ; --> #t
     (call/cc (lambda (k) (same? '(a (b (F) (d e))) '(a (b (c) (d e))) k)))  ; --> #f
     (call/cc (lambda (k) (same? '(a (b)) '(a (b (c) (d))) k)))              ; --> #f
    

    【讨论】:

    • call/cc 与原始问题有什么关系?似乎您只是无缘无故地想在这里使用 CPS;它不会改变太多的实际代码。也就是说,你永远不会(return #t),所以永远不应该返回#t
    • 是的,这是免费的。这是不好的形式吗?您必须明确调用延续是错误的。试试看……
    • 我正在尝试运行它,但 dr-scheme 抱怨缺少 ifs 上的 else 子句。 #t 必须在某个时候出现,不是吗?我也将尝试基于延续的搜索。
    • 嘿 Tyr,这很奇怪,我也在使用 dr-Scheme(没有任何问题)。如果需要,只需在 else 位置添加 #t 即可。 “诀窍”是 cond 形式的 (and (empty?a) (empty?b)) 将隐式返回 true。
    • 当给定字符串、映射、数组或其他东西时它也会失败。我会把 #t 留在 cond 中,特别是因为这是为了教学。不过很好。
    【解决方案3】:

    我也得到了一个持续的答案。但是现在我有两个延续,一个是真的,一个是假的。如果您想对结果进行分支,这很有用。我还包括了 'same?,它隐藏了所有延续,因此您不必处理它们。

    (define (same? a b)
      (call/cc (λ (k) (cont-same? a b (λ () (k #t)) (λ () (k #f))))))
    
    (define (cont-same? a b return-t return-f)
      (define (atest c d)  
        ;; Are they foo?  If they both are, then true
        ;; If they both aren't false
        ;; if they are different, then we are done
        (if (and c d)
            #t
            (if (or c d)
                (return-f)
                #f)))
    
      (if (atest (null? a) (null? b))  ;; Are they both null, or both not null.
          (return-t)
          (if (atest (pair? a) (pair? b))
              (cont-same? (car a)
                          (car b) 
                          (λ () (cont-same? (cdr a) (cdr b) ;; If the head are the same, compare the tails
                                            return-t return-f)) ;; and if the tails are the same, then the entire thing is the same
                          return-f)          
              (if (equal? a b) ;; Both are atoms
                  (return-t)
                  (return-f)))))
    

    【讨论】:

    • @pantenlis 您应该检查答案是否正确,以便问题结束。
    猜你喜欢
    • 2021-10-18
    • 2013-12-02
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多