在lisp中转换树

时间:2015-12-09 15:06:05

标签: tree lisp common-lisp

我试图在(A(B)(C(D)(E))中修改树的表示:( A 2 B 0 C 2 D 0 E 0)。我的代码就像:

(defun transform(l)
 (cond
   ( (null l) NIL)
   ( (and (not (numberp (car l))) (= (cadr l) 0) (null (cddr l)))
        (cons (car l) '(NIL NIL) ))  
   ( (and (not (numberp (car l))) (= (cadr l) 0))
       (cons (cons (car l) '(NIL NIL) ) (list (transform (cddr l))))) 
   ( (not (numberp (car l))) 
         (cons (car l) (list (transform (cddr l)))))
   ( T (transform (cdr l)))
 ))

 (defun subarbst(l nr)
 (cond
    ( (= nr 0) nil)
    ( (atom l) l)
    ( ( numberp (car l)) (cons (car l) (subarbst (cdr l) nr)))
    ( (and (= nr 1) (= (cadr l) 0)) (list (car l) (cadr l))) 
    ( T (cons (car l) (subarbst (cdr l) (+ (car (cdr l)) (- nr 1)))))
)
) 

 (defun subarbdr(l nr)
 (cond 
   ( (= nr 1) (subarbst l nr))
   ( (atom l) l)
   ( T (subarbdr (cddr l) (+ (car (cdr l)) (- nr 1))))
 )
)

(defun transf(l)
(cond 
  ( (null l) nil)
  ( (= 0 (cadr l)) (cons (car l) '(nil nil)))
  ( (= 1 (cadr l)) (list (car l) (transf (subarbst (cddr l) '1))))
  ( (= 2 (cadr l)) (list (car l)
                       (transf (subarbst (cddr l) '1))
                       (transf (subarbdr (cddr l) '2))))
))

但是,而不是第二种形式,我得到的似乎是:( A(B NIL NIL)(C(D NIL NIL)(E NIL NIL))),任何人都可以告诉我为什么我会得到那些&#34 ; NIL"值? .. 提前谢谢!

2 个答案:

答案 0 :(得分:1)

https://stackoverflow.com/a/34193414/1250772给出了答案,作为对显然正在完成相同作业问题的用户的回应的一部分。该解决方案基于将前缀表示法反转为后缀,然后将其解释为构建树的基于堆栈的反向抛光表示法。

巧合的是,来自该答案的以下代码产生与您要求的相同的表示。为了解决那个问题中的顺序遍历问题,我想出了即兴的表示法:

(defun build-tree (syntax)
  (let ((rs (reverse syntax))
        (stack))
    (dolist (item rs (pop stack))  ;; heart of the interpreter loop
      (cond ((integerp item) (push item stack))  ;; integer instruction
            ((symbolp item) (let ((num (pop stack)))  ;; sym instruction
                              ;; construct node using backquote, and
                              ;; put it on the stack.
                              (push `(,item ,@(loop repeat num
                                                    collect (pop stack)))
                                    stack)))))))

答案 1 :(得分:0)

这是一种可能的解决方案,其中使用了辅助函数tree-sequence。请注意,这些函数不会检查输入列表的有效性。

主要功能有一个非常简单的结构:

(defun transform(l)
  (if (null l)
      nil
      (tree-sequence l)))

虽然辅助函数基于以下思想:在每次调用时,要转换的列表的其余部分将传递给函数,该函数返回一对值:

  1. 由函数

  2. 转换的树
  3. 列表的其余部分跟随用于构建第一个值的列表部分。

  4. 这样,在每个递归步骤中,函数本身可以使用第二个值继续转换树。

    这是功能:

    (defun tree-sequence(l)
      (case (cadr l)
        (0 (values (list (car l)) (cddr l)))
        (1 (multiple-value-bind (left-subtree rest-of-list) (tree-sequence (cddr l))
              (values (list (car l) left-subtree) rest-of-list)))
        (t (multiple-value-bind (left-subtree rest-of-list) (tree-sequence (cddr l))
              (multiple-value-bind (right-subtree rest-of-rest) (tree-sequence rest-of-list)
                 (values (list (car l) left-subtree right-subtree) rest-of-rest))))))
    

    请注意,返回的两个值仅在函数tree-sequence中使用,而transform仅使用返回的第一个值,即树。

    最后,请注意,此方法适用于任何类型的元素作为树的节点,包括整数。