【问题标题】:Finding the depth of a list using (constrained) Racket使用(受约束的)Racket 查找列表的深度
【发布时间】:2016-05-10 00:44:05
【问题描述】:

另一个逻辑问题,任务是找到一个列表的深度,例如:给定一个(A B (C D (E))) 的列表,它应该以某种方式指示深度为2(如果包含基本列表,则为3)。我仅限于一组常见的 Racket 功能,我将在下面列出。我在哪里可以遍历列表,但最终在第一个子列表处停止,即:(A (B (C)) (D (E (F)))) 仅作为 2 个出现。

以下是可用功能列表:

  • 缺点、汽车、cdr、定义、报价、if、cond、else
  • 算术的基本形式(+、-、*、/)
  • 非常基本的测试(null?、list?、eq?、数字比较)

到目前为止,这是我的定义,如果有人能将我转向正确的方向,我将不胜感激。

(define (len l) (if (null? l) 0 (+ 1 (len (cdr l)))))

(define A '(A (B) (C (D))))

(define (depth l) (cond

                    [(null? l) '()]

                    [(list? (car l)) (cons (car l) (depth (car l)))]

                    [else (depth (cdr l))]

                    ))

(depth A)

(len (depth A))

【问题讨论】:

    标签: list recursion lisp racket depth


    【解决方案1】:

    每个列表都由当前元素构成,在其car 下,列表的其余部分在cdr 下。

    • 列表的深度与列表其余部分的深度相同,如果那是最深的话。

    • 列表的深度比其car 的深度大一,如果这是最深的话。

    所以,

    (define (depth lst)
      (define a-depth (+ 1 (depth (car lst))))
      (define d-depth (depth (cdr lst)))
      (if (< ..... ) ..... 
        ; or else
        ...... ))
    

    当然,不要忘记处理列表为空或原子(不是一对 - 你不能调用 carcdr非对参数,如果这样做会导致错误):

    • 空列表的深度为零。

    • 原子的深度为零。

    【讨论】:

      【解决方案2】:

      这是我在 Common Lisp 中的定义

      (defun list-depth (list &optional (depth 0))
        (cond ((null list) depth)
              ((atom (first list)) (list-depth (rest list) depth))
              (t (max (list-depth (first list) (1+ depth))
                      (list-depth (rest list) depth)))))
      

      我没有在这台电脑上安装 Racket,所以这里是未经测试的 Scheme/Racket 翻译:

      (define (list-depth lst depth)
        (cond ((null? lst) depth)
              ((not (list? (car lst)) (list-depth (cdr list) depth))
              (else (max (list-depth (car lst) (+ 1 depth))
                         (list-depth (cdr lst) depth)))))
      

      逻辑如下:

      • 如果列表为空,则返回当前深度。
      • 如果列表的car是原子(不是列表),不会增加深度,求列表其余部分(cdr)的深度。
      • 否则,深度将是car 的+1 深度(记住,现在是列表)和列表的cdr 深度之间的最大值。注意car 的深度增加,而不是cdr

      使用的预定义程序:+maxnull?list?carcdrnot

      【讨论】:

        【解决方案3】:

        在我的回答中,列表以 0 的深度开始,每层嵌套增加 1。如果您希望它们从深度 1 开始,您可以在 list-depth 过程中将 (y 0) 更改为 (y 1)

        这可以通过简单的折叠来实现

        (define (list-depth xs (y 0))
          (foldl (λ (x z)
                   (if (list? x)
                       (max z (list-depth x (+ 1 y)))
                       (max z y)))
                 y
                 xs))
        

        foldl 有一个简单的实现

        (define (foldl f y xs)
          (if (null? xs)
              y
              (foldl f (f (car xs) y) (cdr xs))))
        

        这是一些输出

        (list-depth '())                              ; ⇒ 0
        (list-depth '(A))                             ; ⇒ 0
        (list-depth '(A (B)))                         ; ⇒ 1
        (list-depth '(A (B (C))))                     ; ⇒ 2
        (list-depth '(A (B (C (D (E)))) (B (C)) (B))) ; ⇒ 4
        

        如果不想使用折叠抽象,可以将list-depth内的折叠扩展为

        ;; THIS CODE IS BROKEN, DO NOT USE
        ;; @mobiuseng found bugs
        (define (list-depth xs (y 0))
          (cond
            [(null? xs) y]
            [(list? (car xs))
             (max y (list-depth (car xs) (+ 1 y)))]
            [else
             (max y (list-depth (cdr xs) y))]))
        

        两者都产生相同的输出,但是在这个实现中,折叠和最大值这两个概念是纠结在一起的。与第一个相比,看到折叠的胆量使得阅读这个答案变得更加困难。

        折叠的内脏使错误很容易隐藏在最后一个 sn-p 中。我一开始不建议这样写,所以我不会费心去修复它。

        【讨论】:

        • 最后一个代码sn-p:第二个分支不正确:您忽略了cdr可能包含更深层次的事实。在最后一个分支中,max 是多余的,因为 (list-depth (cdr xs) y) 将返回 &gt;= y 值。
        • 很好,@mobiuseng,tyvm。还有一个很好的证明,最后一个 sn-p 过于复杂,很容易隐藏错误!
        猜你喜欢
        • 2010-11-27
        • 2022-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-17
        • 1970-01-01
        • 2010-09-10
        相关资源
        最近更新 更多