我想知道在排序的数组(例如,[1,2,3,4,5,6])和从一个构造完整的二进制搜索树时获得的表示之间是否存在映射这个排序的数组,并将所述二叉搜索树表示为一个数组(例如,[4,2,6,1,3,5],见下图)?
4
2 6
1 3 5
这里有更多的上下文:众所周知,人们可以从中获取一个排序数组,并从中构建一个完整的二元搜索树(有一个唯一的表示)。递归算法是:找到合适的mid(这实际上非常棘手),然后将其视为根 递归左子阵和右子阵。从生成的BST中,可以执行水平顺序遍历(基本上是广度优先搜索)来构造完整BST的数组表示。
我问这个的原因是这个映射与数组的内容无关:它只取决于它的长度。因此,我觉得应该可以将两个数组简洁地表达为彼此的函数。
有什么想法吗?
答案 0 :(得分:2)
树的高度是可预测的roundUp(log2(nodes))
。我们也知道,正确的子树从不大于左子树 - |LS| >= |RS|
。此外,我们还可以计算缺少的节点数,以使树完美:2 ^ (height - 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
是左右子树,它们被定义为BSTs。 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的定义:
在一个完整的二叉树中,每个级别(除了可能是最后一个级别)都被完全填充,并且最后一级中的所有节点都尽可能地离开。
完整的BST是平衡BST的子类,带有一些额外的约束,允许将完整的BST唯一映射到排序的数组,反之亦然。由于完整的BST只是平衡BST的子类,因此 不足以构建平衡的BST。
编辑:
可以通过以下方式更改上述算法以直接构建数组:
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
不同,我们从不使用result
的任何子数组。在任何方法调用中,各个节点的索引都不会改变。
答案 1 :(得分:0)
这就是我想出的。它并不理想,因为它不是我想到的功能,但它节省了构建树然后从中创建数组的工作量。
find_idx(n) {
if n == 1 { return 0; }
h = ceil(lg(n+1)) // height of the tree
f_h = floor(lg(n+1)) // height of the full portion (h or h-1)
m_n = 2^h - 1 // # of nodes if tree were full
f_n = 2^f_h -1 // # of nodes of full portion
return floor(f_n / 2) + min(n - f_n, floor((m_n - f_n) / 2)
}
to_bst_array(array) {
q = new empty queue
res = resulting vector
q.push(array)
while !q.is_empty() {
subarray = q.pop()
idx = find_idx(subarray.len())
res.push(subarray[idx])
if subarray.len() > 1 {
q.push(subarray[..idx]) // slice from 0 to idx
}
if subarray.len() > idx + 1 {
q.push(subarray[idx + 1..]) // slice from idx+1 till end of subarray
}
}
return res
}
答案 2 :(得分:0)
那是我解决此任务的方法,希望您喜欢!)
def GenerateBBSTArray(a):
a.sort()
level = 0
accum = []
elements = []
while len(a) // 2**level > 0:
accum = [elem for elem in a[len(a) // 2**(level + 1)::(len(a) // 2**level) + 1]]
elements.extend(accum)
accum = []
level += 1
return elements
答案 3 :(得分:-2)
表示二叉树搜索(BST)和直接排序数组之间没有直接表示。排序数组之间的唯一关系是当您在BST上运行有序遍历并将其存储在数组中时。