当前位置: 首页 > 知识库问答 >
问题:

如何构造给定后序遍历的BST

吕嘉荣
2023-03-14

我知道有一些方法可以从预序遍历(作为数组)构造树。更常见的问题是构造它,给定顺序和顺序遍历。在这种情况下,虽然inorder遍历是多余的,但它肯定会使事情变得更容易。有谁能给我一个关于后命令遍历的想法吗?迭代和递归都是需要的。

我试着用堆栈迭代地做,但根本无法得到正确的逻辑,所以得到了一个可怕的乱七八糟的树。递归也是如此。

共有1个答案

贺浩壤
2023-03-14

如果您有一个数组来自BST的后序遍历,那么您知道根是数组的最后一个元素。根的左子级占数组的第一部分,由比根小的条目组成。然后跟随右子级,由大于根的元素组成。(两个子级可能都为空)。

________________________________
|             |              |R|
--------------------------------
 left child     right child   root

所以主要的问题是找到左边的孩子结束,右边开始的点。

这两个子级也是从它们的后序遍历中获得的,因此构造它们的方法是相同的,递归的。

BST fromPostOrder(value[] nodes) {
    // No nodes, no tree
    if (nodes == null) return null;
    return recursiveFromPostOrder(nodes, 0,  nodes.length - 1);
}

// Construct a BST from a segment of the nodes array
// That segment is assumed to be the post-order traversal of some subtree
private BST recursiveFromPostOrder(value[] nodes, 
                                   int leftIndex, int rightIndex) {
    // Empty segment -> empty tree
    if (rightIndex < leftIndex) return null;
    // single node -> single element tree
    if (rightIndex == leftIndex) return new BST(nodes[leftIndex]);

    // It's a post-order traversal, so the root of the tree 
    // is in the last position
    value rootval = nodes[rightIndex];

    // Construct the root node, the left and right subtrees are then 
    // constructed in recursive calls, after finding their extent
    BST root = new BST(rootval);

    // It's supposed to be the post-order traversal of a BST, so
    // * left child comes first
    // * all values in the left child are smaller than the root value
    // * all values in the right child are larger than the root value
    // Hence we find the last index in the range [leftIndex .. rightIndex-1]
    // that holds a value smaller than rootval
    int leftLast = findLastSmaller(nodes, leftIndex, rightIndex-1, rootval);

    // The left child occupies the segment [leftIndex .. leftLast]
    // (may be empty) and that segment is the post-order traversal of it
    root.left = recursiveFromPostOrder(nodes, leftIndex, leftLast);

    // The right child occupies the segment [leftLast+1 .. rightIndex-1]
    // (may be empty) and that segment is the post-order traversal of it
    root.right = recursiveFromPostOrder(nodes, leftLast + 1, rightIndex-1);

    // Both children constructed and linked to the root, done.
    return root;
}

// find the last index of a value smaller than cut in a segment of the array
// using binary search
// supposes that the segment contains the concatenation of the post-order
// traversals of the left and right subtrees of a node with value cut,
// in particular, that the first (possibly empty) part of the segment contains
// only values < cut, and the second (possibly empty) part only values > cut
private int findLastSmaller(value[] nodes, int first, int last, value cut) {

    // If the segment is empty, or the first value is larger than cut,
    // by the assumptions, there is no value smaller than cut in the segment,
    // return the position one before the start of the segment
    if (last < first || nodes[first] > cut) return first - 1;

    int low = first, high = last, mid;

    // binary search for the last index of a value < cut
    // invariants: nodes[low] < cut 
    //             (since cut is the root value and a BST has no dupes)
    // and nodes[high] > cut, or (nodes[high] < cut < nodes[high+1]), or
    // nodes[high] < cut and high == last, the latter two cases mean that
    // high is the last index in the segment holding a value < cut
    while (low < high && nodes[high] > cut) {

        // check the middle of the segment
        // In the case high == low+1 and nodes[low] < cut < nodes[high]
        // we'd make no progress if we chose mid = (low+high)/2, since that
        // would then be mid = low, so we round the index up instead of down
        mid = low + (high-low+1)/2;

        // The choice of mid guarantees low < mid <= high, so whichever
        // case applies, we will either set low to a strictly greater index
        // or high to a strictly smaller one, hence we won't become stuck.
        if (nodes[mid] > cut) {
            // The last index of a value < cut is in the first half
            // of the range under consideration, so reduce the upper
            // limit of that. Since we excluded mid as a possible
            // last index, the upper limit becomes mid-1
            high = mid-1;
        } else {
            // nodes[mid] < cut, so the last index with a value < cut is
            // in the range [mid .. high]
            low = mid;
        }
    }
    // now either low == high or nodes[high] < cut and high is the result
    // in either case by the loop invariants
    return high;
}
 类似资料:
  • 在互联网上看到这个问题并试图解决它。我可以解决堆是严格二叉树的情况(通过重复分区前序遍历),但当堆只是一棵完整的二叉树时,我无法找出算法。 例如,如果 是最小堆的预序遍历, 堆的大小为 是堆中的第一个元素(考虑到堆表示为数组) 下一个元素将位于的左子树中 将位于 的左侧子树中 最后一个 个元素将位于 的右子树中 将位于 的右侧子树中 可以通过递归地应用这个逻辑来构造完整的堆。 该解决方案将适用于此

  • 从顺序和后序遍历迭代构造二叉树。 我已经了解了如何使用递归,但我正在寻找一个迭代构造二叉树的答案。 我为inorder和preorder编写了一个算法,但我想知道如何修改inorder和postorder的算法? 注意:它是伪代码,“=”意味着“==” 节点: 二叉树: 子算法树(前序、有序) pre:preorder:Int[],inoorder:Int[] 末端子算法 编辑:我找到了答案

  • 如果我有前序和后序遍历,我可以构建一个不一定是二叉树的树吗?类似的东西: 预购: 后订单: 构建: 我已经读到,如果没有二叉树的顺序遍历,这是不可能的,但是对于非二叉树,有可能只使用前序和后序遍历吗?

  • 问题内容: 我具有以下JSON结构: 如何使用JavaScript进行迭代? 问题答案: 取自jQuery docs:

  • 问题内容: 我需要遍历给定目录内的所有文件并对它们执行一些操作。 如何有效地做到这一点? 问题答案: 原始答案: 上面答案的Python 3.6版本,使用-假设你将目录路径作为str对象包含在名为的变量中: 或递归地使用:

  • 问题内容: 我具有以下JSON结构: 如何使用JavaScript进行迭代? 问题答案: 取自jQuery docs: