Common Lisp Binary Tree
I am trying to write a program in Common Lisp using GNU ClISP to c开发者_JS百科ompile it. I would like to enter a list such as (A(B (C) ()) (D (E) (F (G) ())))
and depending on the first word print out the pre-, in-, or post-order traversal. Example:
(pre '(A(B (C)... etc))
I am having trouble putting my logic into Clisp notation. I currently have the following code:
(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
I get compiling errors saying that I should use a lambda in my pre function. I think this is due to the double (( infront of data because it is expecting a command, but I am not sure what I should put there. I don't think cond would work, because that would hinder the recursive loop. Also, will data L print as it is now? The compiler did not recognize (print (data L))
.
I have been working on this code for over a week now, trying to troubleshoot it myself, but I am at a loss. I would greatly appreciate it if someone could explain what I am doing incorrectly.
Another question that I have is how can I make the program prompt a line to the user to enter the (pre '(A... etc)) so that when I run the compiled file the program will run instead of giving a funcall error?
Thank you for your time.
Short answer: If you want to use if
, note that you'll need a progn
in order to have more than one form in the consequent and alternative cases.
Long answer – also explains how to traverse accumulating the visited nodes in a list:
I guess this is homework, so I won't give you a full solution, but your question shows that you have basically the right idea, so I'll show you an easy, idiomatic way to do this.
First, you're right: The car of an unquoted form should be a function, so basically anything like (foo ...)
, where foo
is not a function (or macro, special form ...), and the whole thing is to be evaluated, will be an error. Note that this does not hold inside special forms and macros (like cond
, for example). These can change the evaluation rules, and not everything that looks like (foo bar)
has to be a form that is to be evaluated by the normal evaluation rules. The easiest example would be quote
, which simply returns its argument unevaluated, so (quote (foo bar))
will not be an error.
Now, about your problem:
An easy solution would be to have an accumulator and a recursive helper function that traverses the tree, and pushes the values in the accumulator. Something like this:
(defun pre (node)
(let ((result (list)))
(labels ((rec (node)
(cond (...
...
...))))
(rec node)
(nreverse result))))
The labels
just introduces a local helper function, which will do the actual recursion, and the outer let
gives you an accumulator to collect the node values. This solution will return the result as a list. If you just want to print each nodes value, you don't need the accumulator or the helper function. Just print instead of pushing, and make the helper your toplevel function.
Remember, that you'll need a base case where the recursion stops. You should check for that in the cond
. Then, you'll need the recursive steps for each subtree and you'll need to push the node's value to the results. The order in which you do these steps decides whether you're doing pre-, in-, or post-order traversal. Your code shows that you already understand this principle, so you'll just have to make it work in Lisp-code. You can use push
to push values to result
, and consp
to check whether a node is a non-empty list. Since there's nothing to do for empty lists, you'll basically only need one test in the cond
, but you can also explicitly check whether the node is null
, as you did in your code.
精彩评论