【问题标题】:how to rebalance a random binary search tree如何重新平衡随机二叉搜索树
【发布时间】:2017-09-19 01:52:52
【问题描述】:

情况如下:有一个平衡的二叉搜索树,它可能被数十个线程访问。所以当我需要插入或删除一个节点时,我不想因为并发而锁定整个树。随着时间的推移,它再次变得不平衡。当树不那么忙于使用时,我终于有机会锁定并重新平衡它。我该怎么做?

或者我可以使用更好的数据结构吗?

【问题讨论】:

  • 您是怎么遇到这种情况的?只有当我们知道用例时,才能决定更好的数据结构。树是只被读取还是更新太频繁?
  • 删除节点时,只需将其标记为已删除,但保留在树中。当您有时间锁定和重新平衡时,按顺序遍历旧树,并从所有未标记为已删除的节点构建一棵新树。
  • @displayName 一天中的大部分时间,树都在高并发读取,同时它也在频繁更新。但是每隔几个小时,读取并发就会冷却下来,锁定就可以了。
  • 我有一个解决方案,但它可能不是一个很好的解决方案 - 使用树的两个副本。允许从两者读取。但是在更新时,锁定一棵树并更新它,同时让读取转到另一棵树。然后更新第二个,让读取转到第一个。
  • @displayName 每个创意:)

标签: data-structures tree binary-search-tree avl-tree


【解决方案1】:

您实际上可以使用Day-Stout-Warren algorithm 重新平衡它。它在节点数量上是线性的,因此可能需要一段时间。此外,这种方法提出了一个问题:如果在不重新平衡正在读取的树的时间间隔内,它很快变得严重不平衡,并且所有后续读取都在 O(N) 而不是 O(logN) 中完成,该怎么办? ?为了不锁定东西而让性能损失几个小时可以吗?你确定会在性能上获胜吗?

如果你可以容忍缺乏线性化(即你写了一个值,但是当你没有找到它之后立即搜索它;它最终会在那里,但 100ms-10s 可能会过去),你可以实现一个“写时复制” " 树:所有写入都由一个线程完成(使用重新平衡),并且您定期将树克隆为只读副本,该副本可供读取线程使用而无需任何并发控制,您只需要以原子方式发布它。如果树是在可以作为一个整体复制并作为一个整体进行释放/垃圾收集的连续内存块之上实现的,则可以特别快地完成。

另一个选项是使用并发skip list:它提供对数平均案例搜索/删除/插入时间,并且更容易并行化。如果您碰巧使用它,有一个标准的无锁implementation for Java。您可以找到有关并发跳过列表和平衡搜索树的更多信息here。特别是,您会发现其中提到了 chromatic tree,这是一种针对并发重新平衡进行了优化的二叉搜索树。

【讨论】:

  • 我做了一些测试,是的,如果我不重新平衡树,性能不会那么好。如果插入后几分钟没有找到数据也没关系,所以“写时复制”是我没有想到的一个很好的解决方案。非常感谢你!
猜你喜欢
  • 1970-01-01
  • 2013-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-13
  • 1970-01-01
相关资源
最近更新 更多