如何从已排序的流中最好地构建持久二叉树
Posted
技术标签:
【中文标题】如何从已排序的流中最好地构建持久二叉树【英文标题】:How to best build a persistent binary tree from a sorted stream 【发布时间】:2018-06-19 19:44:13 【问题描述】:对于一个辅助项目,我想要一种从排序流生成持久二叉搜索树的简单方法。经过一些粗略的搜索后,我只能找到涉及存储排序数组的技术描述,您可以在其中通过索引访问任何元素。我最终写了一些有用的东西,但我认为这是一个很好的领域,一个规范的例子可能记录在某个地方(并且可能有一个名字)。
为了清楚起见,我制作了转换代码。 (也很短)
object TreeFromStream
sealed trait ImmutableTree[T]
def height: Int
case class ImmutableTreeNode[T](
value: T,
left: ImmutableTree[T],
right: ImmutableTree[T]
) extends ImmutableTree[T]
lazy val height = left.height + 1
case class NilTree[T]() extends ImmutableTree[T]
def height = 0
@tailrec
def treeFromStream[T](
stream: Stream[T],
tree: ImmutableTree[T] = NilTree[T](),
ancestors: List[ImmutableTreeNode[T]] = Nil
): ImmutableTree[T] =
(stream, ancestors) match
case (Stream.Empty, _) =>
ancestors.foldLeft(tree) case(right, root) => root.copy(right=right)
case (_, ancestor :: nextAncestors) if ancestor.left.height == tree.height =>
treeFromStream(stream, ancestor.copy(right=tree), nextAncestors)
case (next #:: rest, _) =>
treeFromStream(
rest, NilTree(),
ImmutableTreeNode(next, tree, NilTree()) :: ancestors
)
【问题讨论】:
en.wikipedia.org/wiki/Self-balancing_binary_search_tree 我不会读或写scala,所以不会评论你的代码。如果您事先知道节点的数量,您可以在 O(n) 时间内在线生成一个complete balanced tree,用于长度为 n 的排序输入。如果事先不知道输入大小,可以生成根的左子树完美,右子树完整的树。如果输入大小是 2^k-1 的形式,那么 while 树将是完美的。该算法将树片段累积在堆栈中,并在新元素到达时将它们缝合在一起。 @Gene:我提前不知道尺寸的情况听起来像是我感兴趣的。你能给我指个引文吗? 你可以看看这篇文章:cglab.ca/~dana/pbst 【参考方案1】:要创建平衡树,我猜你想这样做,你需要至少访问每个节点一次。首先,将所有节点收集到一个缓冲区中,然后将缓冲区递归转换为树:
def tfs[T](stream: Stream[T]): ImmutableTree[T] =
val ss = scala.collection.mutable.ArrayBuffer.empty[T]
def treeFromSubsequence(start: Int, end: Int): ImmutableTree[T] =
if (end == start) NilTree()
else if (end - start == 1) ImmutableTreeNode(ss(start), NilTree(), NilTree())
else
val mid = (end - start) / 2
ImmutableTreeNode(ss(mid), treeFromSubsequence(start, mid), treeFromSubsequence(mid + 1, end))
stream.foreach x => ss += x
treeFromSubsequence(0, ss.length)
它将准确地访问每个值两次,一次收集它,一次将它放入树的值字段中。
【讨论】:
您不需要预先设置所有节点。最简单的例子是self-balancing binary search tree,其中有很多类型。可能有针对有序插入优化的版本。 您正在对数组中的所有元素进行随机访问。该问题指出,此答案在其他地方找到“经过一些粗略的搜索,我只能找到涉及存储排序数组的技术描述,您可以在其中通过索引访问任何元素。”问题中提供的代码已经可以通过流式传输来完成此操作。 @JimMischel 你能更明确一点吗?哪些实现使用了持久二叉树? @StevenNoble 这些实现都不是持久二叉树,但可以为此目的修改一些。我不是持久数据结构方面的专家,所以我无法提供任何具体细节。我在这里评论的重点是,不需要预先知道节点的数量或节点本身。 如果您不能或不会利用流已排序或节点数已知的知识,那么您将拥有O(N log N)
算法。我提出的算法是O(N)
以上是关于如何从已排序的流中最好地构建持久二叉树的主要内容,如果未能解决你的问题,请参考以下文章