在COMMON LISP中使用预订和顺序进行树重建

时间:2013-02-08 21:44:43

标签: tree lisp common-lisp binary-tree allegro-cl

由于我一直在学习LISP并阅读实用的常见lisp,我发现了问题,并试图解决这些问题,我一直坚持这个特殊的问题,不确定如何处理它,所以想要一些帮助/建议。

我需要能够从预订中按顺序创建一个后序树

例如,如果给出以下内容:

预购:A B D E C F

按顺序:D B E A C F

输出将是后序:D E B F C A

从我所看到的,inorder的第一个元素始终是postorder的第一个元素,所以我开始编写代码来反映这一点:

(defun tree-recovery (preorder inorder)
  (let (root)
    (setf root (first inorder))))

但我不确定从这里去哪里,任何帮助都将不胜感激!感谢

1 个答案:

答案 0 :(得分:2)

如果我们命名我们的函数tree-recovery,让它恢复树 而不是建立后序序列。 (有人比我聪明 需要在没有实际重建的情况下解决问题 树)。

Inorder和postorder以相同的元素开始,但该元素是 root:预订序列的第一个元素是根。

假设所有序列元素都是,让我们恢复树 与EQL相当的非零原子。我们将代表 leaf 作为 atom的值,其他节点(list root left right)和空 子树为NIL。

(defun tree-recovery (preorder inorder)
  (if (rest preorder)
      (let* ((root (pop preorder))
             (inorder-root-tail
               (member root inorder))
             (inorder-left
               (ldiff inorder inorder-root-tail))
             (left-length
               (length inorder-left))
             (inorder-right
               (rest inorder-root-tail))
             (preorder-left
               (subseq preorder 0 left-length))
             (preorder-right
               (subseq preorder left-length)))
        (list root
              (tree-recovery preorder-left inorder-left)
              (tree-recovery preorder-right inorder-right)))
      (first preorder)))

对于空树,我们返回NIL。对于一个叶节点的琐碎树,我们 返回一个值。

对于其他树,我们首先从preorder中弹出根元素(其中 这是第一次)。然后我们找到一个以根元素开头的子列表 inorder。我们使用它来获得与我们相对应的inorder 左子树和一块inorder对应我们的权利 子树。知道左子树的大小,我们左右 preorder很容易。

现在,当我们有一棵树时,进行后序遍历很容易:

(defun postorder (tree)
  (and tree ;; non-empty
       (if (consp tree) ;; non-leaf
           (destructuring-bind (root left right) tree
             (append (postorder left)
                     (postorder right)
                     (postorder root)))
           (list tree))))

让我们试试:

(postorder 
 (tree-recovery '(a b d e c f)
                '(d b e a c f)))
=> (D E B F C A)

似乎工作。