在尝试理解二进制(搜索)树时,我偶然发现了BST是否可以有效地存储在平面阵列中的问题(即,没有浪费空间)。谷歌搜索和在论坛(包括SO)搜索后,我没有找到任何让我满意的东西。大多数人希望存储BT(l=2*i+1
,r=2*i+2
)或接受节点的空子节点表示为nil
值(并且存储类似,不必要地占用空间)的事实。 / p>
所以我编写了自己的算法,利用了BST中的子节点具有特定排序属性(小于root:left
,大于root:right
)这一事实。
要存储BST,我只是将其线性地写入数组,深度优先。这发生在O(n)
中,递归到树的子节点中。那么数组的长度恰好为n
个条目,n
是BST中的节点数。
要从数组重建BST,我在数组中遇到新条目时遵循两条规则:
下一个左侧节点(如果存在)是下一个比当前节点小的节点。
下一个正确的节点(如果存在)是下一个...
left
left
分支这也发生在O(n)
。
对于非常非常大的随机结构树(只要它们是BST),它的效果非常好。经验测试从未表现出任何问题。我在C ++ here中创建了一个工作代码示例,两个转换函数是toArray和fromArray。
现在问我的问题: 这概括了吗?我害怕用这个来监督关键问题。事实上,我还没有在网上发现任何其他内容,这让我想知道是否
a )我太傻了,无法找到它,
b )这是常识,没有人谈论它或
c )这是完全错误的。
我会非常感谢任何精通这个主题的人来启发我。
非常感谢。
修改
在谷歌更多地完全忽略阵列细节之后,我找到了几个有效的解决方案。最突出的一个(如here和here所述)是使用预订遍历来存储BST。答案 0 :(得分:1)
最终,我自己找到了解决方案。用于从BST深度优先创建的数组重建BST的技术基于预先遍序。
我找到了解决方案here,并在我自己的BST课程here中实现了该解决方案。重要的部分如下:
bool BinarySearchTree::fromArrayPreorderTraversal(std::vector<unsigned int> vecArray, unsigned int& unCurrentIndex, unsigned int unMin, unsigned int unMax) {
bool bResult = false;
if(unCurrentIndex < vecArray.size()) {
unsigned int unVal = vecArray[unCurrentIndex];
if(unVal > unMin && unVal < unMax) {
bResult = true;
this->setKey(unVal);
unCurrentIndex++;
if(unCurrentIndex < vecArray.size()) {
if(!this->left(true)->fromArrayPreorderTraversal(vecArray, unCurrentIndex, unMin, unVal)) {
this->setLeft(NULL);
}
if(!this->right(true)->fromArrayPreorderTraversal(vecArray, unCurrentIndex, unVal, unMax)) {
this->setRight(NULL);
}
}
}
}
return bResult;
}
这里是以下形式的BST:
10
/ \
5 20
/ \ \
2 7 30
/
1
可用作预订遍历数组:
10 5 2 1 7 20 30
首先是父节点,然后是左子节点,然后是右子节点(递归地)。这是BST的深度优先表示。
该算法获取有效范围的键,以接受left
或right
侧的新节点作为参数(此处为unMin
和unMax
)并基于那,决定是否应该创建节点。完整的BST包括其原始结构以这种方式重建。
此时间复杂度(根据上面的参考)是O(n)
。由于没有浪费空间,空间复杂度也是O(n)
。
这个算法比我在问题中提出的算法更优雅。它似乎也是进行这种重建的一般方式。