algorithm – 排序列表以完成BST数组表示

我想知道在排序的数组(例如,[1,2,3,4,5,6])和当从这个排序的数组构造完整的二进制搜索树时获得的表示之间是否存在映射,并且将所述二叉搜索树表示为数组(例如,[4,2,6,1,3,5],见下图)?

     4
  2     6
1   3  5

这里有一些更多的上下文:众所周知,人们可以从中获取一个有序数组并从中构造一个完整的二进制搜索树(有一个唯一的表示).递归算法是:找到合适的mid(这实际上非常棘手),然后将其视为根
递归左子阵和右子阵.从生成的BST中,可以执行水平顺序遍历(基本上是广度优先搜索)来构造完整BST的数组表示.

我问这个的原因是这个映射与数组的内容无关:它只取决于它的长度.因此,我感觉应该可以将两个数组简洁地表达为彼此的函数.

有什么想法吗?

最佳答案
树的高度是可预测的roundUp(log2(节点)).我们也知道,正确的子树永远不会大于左子树 – | LS | > = | RS |.此外,我们可以计算缺少的节点数量,以使树完美:2 ^(高度 – 1) – arr.length.这允许我们预测如何在子树之间分配节点:

findRoot(int[] arr , int maxLeaves , int maxLevelL)
    //maxLeaves is the number of leaves on the maximum-level
    int l = min(maxLevelL / 2 , maxLeaves)
    return (arr.length - maxLeaves) / 2 + l

node buildTree(int[] arr , int maxLeaves , int maxLevelL)
    if maxLevelL == 0
        return null

    node result
    int rootidx = findRoot(arr , maxLeaves)

    result.val = arr[rootidx]

    result.left = buildTree(arr.subarray(0 , rootidx) , Math.min(maxLeaves , rootidx - 1) , maxLevelL / 2)
    result.right = buildTree(arr.subarray(rootidx + 1 , arr.length) , Math.max(0 , maxLeaves - rootidx - 1) , maxLevelL / 2)

    return node

基本思想如下:所有完整的BST共享一个属性,关于BST的递归定义:(LS,R,RS)OR null,其中LS和RS是左子树和右子树,它们也被定义为BST. LS和RS都是完整的,其中至少有一个必须是完美的.我们可以很容易地预测两者中哪一个是完美的:在最高级别适合m个节点,但在数组中我们缺少x个节点来构建完美的树.从而:

if m - x == m / 2 then both are complete and the height of RS is height(LS) - 1
if m - x < m / 2 RS is perfect, LS only complete but not perfect
if m - x > m / 2 LS is perfect, RS only complete but not perfect
if m - x == 0 both LS and RS are perfect and of equal height

我们可以使用以下规则找到树的根:
计算将放置在最高级别的左(l)和右(r)子树上的节点数.现在我们可以轻松地从树中删除这些节点,计算完美BST的根,然后将隐藏的左右节点添加回树中:root =(arr.length – (l r))/ 2 l

E.g.:
Input:   1  2  3  4  5 
Nodes on maxLevel: 2
maxLevelL: 4

l = 2
r = 0

root_idx = (arr.length - (l + r)) / 2 + l =
     = (5 - 2) / 2 + 2 = 
     = 3

Apply this algorithm recursively to define subtrees:
...

result:
                  4
                /   \
               2     5
             /   \
            1     3

注意:
我还没有测试过这段代码.可能是它仍然包含一些需要修复的算术不足.但逻辑是正确的.这应该只是表示将索引从一个数组重新映射到另一个数组的方法.实际的实现可能与我提供的代码有很大的不同.

在第二次讨论之后,这里是完整BST的定义:

In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible.

from wikipedia

完整的BST是平衡BST的子类,具有一些额外的约束,允许将完整BST唯一映射到排序数组,反之亦然.由于完整的BST只是平衡BST的子类,因此建立平衡的BST是不够的.

编辑:
可以通过以下方式更改上述算法以直接构建数组:

>树的根有索引0
>索引为n的节点的左子节点具有索引(n 1)* 2 – 1
>索引为n的节点的右子节点具有索引(n 1)* 2

通常这些访问操作是在基于1的数组上完成的,但为了方便起见,我将它们更改为匹配基于0的数组

因此我们可以重新实现buildTree来直接生成一个数组:

node buildTree(int[] arr , int maxLeaves , int maxLevelL , 
          int[] result , int nodeidx)
    if maxLevelL == 0
        return

    int rootidx = findRoot(arr , maxLeaves)

    //insert value into correct position of result-array
    result[nodeidx] = arr[rootidx]

    //build left subtree
    buildTree(arr.subarray(0 , rootidx) , Math.min(maxLeaves , rootidx - 1) , maxLevelL / 2 , 
              result , (nodeidx + 1) * 2 - 1)

    //build right subtree
    buildTree(arr.subarray(rootidx + 1 , arr.length) , Math.max(0 , maxLeaves - rootidx - 1) , maxLevelL / 2 ,
              result , (nodeidx + 1) * 2)

请注意,与arr不同,我们从不使用任何结果的子数组.在任何方法调用中,各个节点的索引永远不会改变.

转载注明原文:algorithm – 排序列表以完成BST数组表示 - 代码日志