【问题标题】:Scheme - program to count the number of pairs (SICP ex 3.17) - is my solution correct?方案-计算对数的程序(SICP ex 3.17)-我的解决方案正确吗?
【发布时间】:2020-09-02 02:55:00
【问题描述】:

我需要设计一个程序来返回任何结构中不同对的数量。我的程序正确吗?我在网上找到的解决方案都大相径庭。

(define (count-pairs x)
  (define (count-cdr x)
    (if (not (pair? x))
        0
        (+ (count-pairs (car x))
           (count-cdr (cdr x)))))
  (if (not (pair? x))
      0
      (+ (count-pairs (car x))
         (count-cdr (cdr x))
         1)))

【问题讨论】:

    标签: list scheme lisp sicp


    【解决方案1】:

    请注意,该问题要求 any 结构中 distinct 对的数量,因此我们必须小心并避免多次计算同一对,即使它在结构内的不同位置!还要注意提示:

    遍历结构,维护一个辅助数据结构,用于跟踪哪些对已经被计数

    必须跟踪您找到的配对,并检查它们是否重复,您的解决方案完全忽略了提示。这对我有用:

    (define (count-pairs x)
      (let ((acc '()))
        (define (count lst)
          (cond ((or (not (pair? lst)) (memq lst acc)) 0)
                (else (set! acc (cons lst acc))
                      (+ 1 (count (car lst)) (count (cdr lst))))))
        (count x)))
    

    这里有一些测试可以证明我的观点:

    (define l1 (cons 1 (cons 2 (cons 3 null))))
    
    (define x1 (cons null null))
    (define y1 (cons x1 x1))
    (define l2 (cons y1 null))
    
    (define x2 (cons 1 (cons 2 null)))
    (define l3 (cons x2 x2))
    
    (define x3  (cons null null))
    (define y3  (cons x3 x3))
    (define l4 (cons y3 y3))
    
    (count-pairs l1)
    => 3
    (count-pairs l2)
    => 3
    (count-pairs l3)
    => 3
    (count-pairs l4)
    => 3
    

    【讨论】:

      【解决方案2】:

      这是我认为在 Scheme 中相当自然的方法。尽管人们(尤其是我)痴迷于使流程迭代而不是递归,而不是太多(为什么堆栈空间比这段代码创建的潜在巨大议程更有价值?),为这种类型编写迭代程序是相当不错的东西。

      这个函数有两个列表:

      • 它已经看过的配对列表,因此它可以知道它是否看过配对
      • 它需要处理的事情的议程,在处理汽车之前,它会将它看到的新对的 cdr 推送到该议程上。

      然后该过程是检查它正在看的东西是否是一对并且未被看到。如果这是真的,那么它将计数加一并处理这对汽车,将 cdr 推到议程上,并将整个车对推到已看到的列表中。如果这不是真的,那么它要么将某些事情从议程中拉出来进行处理,或者,如果没有议程,它就完成了,计数就是答案。

      请注意,在现实生活中,cp-loop 将命名为 let,这使我认为迭代更加清晰。

      (define (count-pairs thing)
        (define (cp-loop it count agenda seen)
          (cond
            [(and (pair? it) (not (memq it seen)))
             ;; It's a pair, and we have not seen it, so:
             ;; - add one to the count
             ;; - loop on its car
             ;; - pushing its cdr onto the agenda
             ;; - note we've seen it
             (cp-loop (car it)
                      (+ count 1)
                      (cons (cdr it) agenda)
                      (cons it seen))]
            [(not (null? agenda))
             ;; Either it is not a pair, or we've seen it
             ;; But there is more to do, so:
             ;; - pick the first agenda item & try that
             (cp-loop (first agenda)
                      count
                      (rest agenda)
                      seen)]
            [else
             ;; it's not a pair or we have seen it
             ;; and there is no agenda: we are done
             count]))
        (cp-loop thing 0 '() '()))
      

      现在:

      > (define o1 '(1 . (2 . (3 . ()))))
      > o1
      '(1 2 3)
      > (count-pairs o1)
      3
      > (define o2 '(1 . (2 . (3 . (4 . 5)))))
      > o2
      '(1 2 3 4 . 5)
      > (count-pairs o2)
      4
      > (define o3 (cons o1 o1))
      > (count-pairs o3)
      4
      > o3
      '((1 2 3) 1 2 3)
      > (count-pairs '((1 2 3) 1 2 3))
      7
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多