如果我们命名我们的函数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)
似乎工作。