2

由于我一直在学习 LISP 并阅读实用的通用 lisp,因此我发现了一些问题并试图解决这些问题,我陷入了这个特定问题,并且不确定如何解决它,因此希望得到一些帮助/建议。

我需要能够从它的前序和有序创建一个后序树

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

预购:ABDECF

顺序:DBEACF

输出将是后序:DEBFCA

从我所见,中序的第一个元素始终是后序的第一个元素,所以我开始编写代码来反映这一点:

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

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

4

1 回答 1

2

如果我们命名我们的函数tree-recovery,让它恢复树而不是构建后序序列。(需要比我更聪明的人来解决问题,而无需实际重建树)。

中序和后序从同一个元素开始,但该元素 不是根:前序列的第一个元素是根。

让我们恢复树,假设所有序列元素都是可比较的非零原子EQL。我们将叶子表示为 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)

似乎工作。

于 2013-02-08T22:20:54.497 回答