Common Lisp二叉树

时间:2011-10-10 02:16:57

标签: common-lisp binary-tree clisp

我正在尝试使用GNU ClISP在Common Lisp中编写一个程序来编译它。我想输入一个列表,例如(A(B (C) ()) (D (E) (F (G) ()))),并根据打印出前,中,或后顺序遍历的第一个单词。示例:

(pre '(A(B (C)... etc))

我无法将逻辑输入Clisp表示法。我目前有以下代码:

(defun leftchild (L)(cadr L))

(defun rightchild (L)(caddr L))

(defun data (L)(car L))

(defun pre (L)(if (null L) '()((data L)(pre(leftchild L))(pre(rightchild L)))))

... similar in and post functions

我得到编译错误,说我应该在我的pre函数中使用lambda。我认为这是由于双重((数据前面因为它期待一个命令,但我不确定我应该放在那里。我不认为cond会起作用,因为这会妨碍递归循环。此外,数据L会像现在一样打印吗?编译器无法识别(print (data L))

我已经在这个代码上工作了一个多星期,试图自己排除故障,但我不知所措。如果有人能够解释我做错了什么,我将不胜感激。

我的另一个问题是如何让程序提示用户输入一行(pre'(A ... etc)),这样当我运行编译的文件时,程序将运行而不是给出一个funcall错误?

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

简短回答:如果您想使用if,请注意您需要progn才能在后续和替代案例中包含多个表单。


长答案 - 还解释了如何遍历在列表中累积受访节点:

我想这是作业,所以我不会给你一个完整的解决方案,但你的问题表明你基本上有正确的想法,所以我会告诉你一个简单,惯用的方法来做到这一点。

首先,你是对的:一个不带引号的形式的汽车应该是一个函数,所以基本上像(foo ...)foo不是函数(或宏,特殊形式......) ),整个事情是要评估,将是一个错误。请注意,这不适用于特殊形式和宏(例如cond)。这些可以更改评估规则,而不是看起来像(foo bar)的所有内容都必须是要由正常评估规则评估的表单。最简单的示例是quote,它只会返回其参数未评估,因此(quote (foo bar)) 会出错。

现在,关于你的问题:

一个简单的解决方案是使用累加器和遍历树的递归辅助函数,并将值推送到累加器中。像这样:

(defun pre (node)
  (let ((result (list)))
    (labels ((rec (node)
               (cond (...
                      ...
                      ...))))
      (rec node)
      (nreverse result))))

labels只引入了一个本地帮助函数,它将执行实际的递归,而外let为您提供了一个累加器来收集节点值。此解决方案将结果作为列表返回。如果您只想打印每个节点值,则不需要累加器或辅助函数。只需打印而不是推动,并使助手成为你的顶级功能。

请记住,您需要一个递归停止的基本案例。您应该在cond中查看该内容。然后,您将需要每个子树的递归步骤,并且您需要将节点的值推送到结果。您执行这些步骤的顺序决定了您是在进行预订,中间或后订单遍历。您的代码表明您已经理解了这个原则,因此您只需要使用Lisp代码即可。您可以使用push将值推送到resultconsp以检查节点是否为非空列表。由于空列表无关,因此基本上只需要在cond中进行一次测试,但您也可以像在代码中一样明确检查节点是否为null