【问题标题】:LISP Displaying binary tree level by levelLISP 逐级显示二叉树
【发布时间】:2008-12-21 12:48:16
【问题描述】:

我有一个看起来像 (A (B (C D)) (E (F))) 的列表,它代表这棵树:

      A
    /  \
  B      E
 / \    /
C   D  F

如何将其打印为 (A B E C D F) ?

据我所知:

((lambda(tree) (loop for ele in tree do (print ele))) my-list)

但它会打印:

A
(B (C D))
(E (F))
NIL

我对 Common LISP 还很陌生,所以可能有一些我应该使用的功能。如果是这样,请启发我。

谢谢。

【问题讨论】:

  • 这看起来像家庭作业。如果是,您应该说明。
  • 这看起来像作业,但我会提示:这称为广度优先遍历。

标签: lisp binary-tree


【解决方案1】:

从表面上看您的问题,您希望以“广度优先”的顺序打印出节点,而不是使用标准的深度优先顺序之一:“按顺序”或“预购”或'后订购'。

  • 按顺序:C B D A E F
  • 预购:A B C D E F
  • 后订单:C D B F E A

  • 请求的顺序:A B E C D F

在您的树结构中,每个元素可以是一个原子,也可以是一个包含一个元素的列表,或者一个包含两个元素的列表。列表的第一个元素始终是原子。

我认为伪代码需要大致如下:

Given a list 'remains-of-tree':
    Create empty 'next-level' list
    Foreach item in `remains-of-tree`
        Print the CAR of `remains-of-tree`
        If the CDR of `remains-of-tree` is not empty
             CONS the first item onto 'next-level'
             If there is a second item, CONS that onto `next-level`
    Recurse, passing `next-level` as argument.

我 100% 确定可以清理它(这看起来像微不足道的尾递归,除此之外)。不过,我认为它有效。

Start: (A (B (C D)) (E (F)))
Level 1:
Print CAR: A
Add (B (C D)) to next-level: ((B (C D)))
Add (E (F)) to next-level: ((B (C D)) (E (F)))
Pass ((B (C D) (E (F))) to level 2:
Level 2:
Item 1 is (B (C D))
Print CAR: B
Push C to next-level: (C)
Push D to next-level: (C D)
Item 2 is (E (F))
Print CAR: E
Push F to next-level: (C D F)
Pass (C D F) to level 3:
Level 3:
Item 1 is C
Print CAR: C
Item 2 is D
Print CAR: D
Item 3 is F
Print CAR: F

【讨论】:

    【解决方案2】:

    您表示列表的方式似乎不一致。对于您的示例,我想应该是:(A ((B (C D)) (E (F))))。这样,一个节点始终是叶子节点或列表,其中 car 是叶子节点,cadr 是子节点。

    由于这个错误,我假设这不是家庭作业。这是一个递归解决方案。

    (defun by-levels (ts)
      (if (null ts)
          '()
          (append
           (mapcar #'(lambda (x) (if (listp x) (car x) x)) ts)
           (by-levels (mapcan #'(lambda (x) (if (listp x) (cadr x) '())) ts)))))
    

    by-levels 获取节点列表并收集顶级节点的值,并递归查找下一个子节点以用作下一个节点。

    现在,

    (defun leafs-of-tree-by-levels (tree)
      (by-levels (list tree)))
    
    (leafs-of-tree-by-levels '(a ((b (c d)) (e (f)))))
    ; (A B E C D F)
    

    我希望这是有道理的。

    【讨论】:

      【解决方案3】:

      我的 Lisp 有点生疏了,但正如 Jonathan 建议的那样,应该使用广度优先的树遍历来做到这一点 - 类似这些思路

      编辑:我想我之前读这个问题有点太快了。你所拥有的基本上是一个函数应用程序的语法树,所以这里是修改后的代码。我从您对问题的描述中假设,如果 C 和 D 是 B 的孩子,那么您的意思是写 (B (C)(D))

      ; q is a queue of function calls to print
      (setq q (list the-original-expression))
      ; for each function call
      (while q
        ; dequeue the first one
        (setq a (car q) q (cdr q))
        ; print the name of the function
        (print (car a))
        ; append its arguments to the queue to be printed
        (setq q (append q)(cdr a))
        )
      

      这是历史:

               q: ( (A (B (C)(D))(E (F))) )
      print: A
               q: ( (B (C)(D))(E (F)) )
      print: B
               q: ( (E (F))(C)(D) )
      print: E
               q: ( (C)(D)(F) )
      print: C
               q: ( (D)(F) )
      print: D
               q: ( (F) )
      print: F
               q: nil
      

      【讨论】:

      • 对 list 使用 cons 有什么区别?我都试过了,但不管怎样,它都被打印为列表(没有点)。
      • 我之前看问题有点太快了,所以我修改了代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      • 2019-08-15
      相关资源
      最近更新 更多