If we name our function tree-recovery
, let it recover the tree
instead of building the postorder sequence. (Someone smarter than me
is required to solve the problem without actual reconstruction of the
tree).
Inorder and postorder start with the same element, but that element is
not root: the first element of preorder sequence is the root.
Let's recover the tree, assuming that all sequence elements are
non-nil atoms comparable by EQL
. We will represent a leaf as a
value of atom, other nodes as (list root left right)
, and an empty
subtree as 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)))
For empty trees we return NIL. For trivial trees of one leaf node, we
return a value.
For other trees, we first pop the root element from preorder
(where
it's first). Then we find a sublist starting with the root element in
inorder
. We use it to get a piece of inorder
corresponding to our
left subtree and a piece of inorder
corresponding to our right
subtree. Knowing the size of our left subtree, we get left and right
piece of preorder
easily.
Now when we have a tree, doing postorder traversal is easy:
(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))))
Let's try:
(postorder
(tree-recovery '(a b d e c f)
'(d b e a c f)))
=> (D E B F C A)
Seems to work.