函数式编程中哪种自平衡树最简单?
我正在 Haskell 中设计一棵自平衡树。作为一种练习,因为握在后手上感觉很好。
以前在 C 和 Python 中,我更喜欢 Treaps 和 Splay Trees,因为它们的平衡规则简单。我一直不喜欢 R/B 树,因为它们似乎比它们的价值更多的工作。
现在,由于 Haskell 的函数性质,事情似乎发生了变化。我可以用 10 行代码编写一个 R/B 插入函数。另一方面,Treaps 需要包装来存储随机数生成器,而 Splay Trees 则很难从上到下进行。
所以我想问你是否有种植其他类型树木的经验? 哪些更擅长利用函数式语言的模式匹配和自上而下的性质?
I'm designing a self balancing tree in Haskell. As an exercise and because it is nice to have in your back hand.
Previously in C and Python I preferred Treaps and Splay Trees due to their simple balancing rules. I always disliked R/B Trees, since they seemed like more work than they were worth.
Now, due to the functional nature of Haskell, things seem to have changed. I can write a R/B insert function in 10 lines of code. Treaps on the other hand requires wrapping to store the random number generator, and Splay Trees are a pain to do top-down.
So I'm asking if you have experience with other types of trees?
Which ones are better at utilizing the pattern matching and top-down nature of functional languages?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,我想没有太多参考资料或研究来回答这个问题。相反,我花时间尝试了你们不同的想法和树木。我没有找到比 RB 树更好的东西,但这也许只是搜索偏差。
RB 树可以通过四个简单规则进行(插入)平衡,如 所示Chris Okasaki:
AVL树可以通过类似的模式匹配方式来平衡。然而,规则也没有压缩:
由于 AVL 树通常被认为不如 RB 树,因此它们可能不值得额外的麻烦。
理论上,AA 树可以通过以下方式轻松平衡:
但不幸的是 Haskell 不喜欢
n
的重载。 AA 树的不太标准的实现(不使用等级,而是使用更类似于 R 和 B 的东西)可能会很好地工作。展开树很困难,因为您需要关注单个节点,而不是树的静态结构。可以通过合并插入和展开来完成。
在功能环境中也很难进行 Treap,因为您没有全局随机生成器,但需要在每个节点中保留实例。这可以通过将生成优先级的任务留给客户端,但即便如此,您也无法使用模式匹配进行优先级比较。
Ok, I guess there wasn't a lot of references or research for answering this question. Instead I've taken the time to try your different ideas and trees. I didn't find anything a lot better than RB trees, but perhaps that's just search bias.
The RB tree can be (insertion) balanced with four simple rules, as shown by Chris Okasaki:
AVL trees can be balanced in a similar pattern matching way. However the rules don't compress as well:
As AVL trees seams to generally be considered inferior to RB trees, they are probably not worth the extra hassle.
AA trees could theoretically be balanced nice and easily by:
But unfortunately Haskell don't like the overloading of
n
. It is possible that a less standard implementation of AA trees, not using ranks, but something more similar to R and B, would work well.Splay trees are difficult because you need to focus on a single node, rather than the static structure of the tree. It can be done by merging insert and splay.
Treaps are also uneasy to do in a functional environment, as you don't have a global random generator, but need to keep instances in every node. This can be tackled by leaving the task of generating priorities to the client, but even then, you can't do priority comparison using pattern matching.
正如你所说,红黑树并不难使用。你看过手指树吗?您可能有兴趣使用 拉链。您可能会感兴趣的另一棵树是AA 树是红黑树的简化。
As you say Red Black trees aren't that hard to use. Have you given finger trees a look? You might be interested in augmenting your base data structure with something like a zipper. Another tree you might find interesting is the AA tree it is a simplification of Red Black Trees.
这是已经实施的方案。
Haskell 中有平衡树的良好实现,例如 Data.Map 和 Data.Set。他们不能满足您的需求吗?不要重新实现、重用。
It's the one that's already implemented.
There are fine implementations in Haskell of balanced trees such as Data.Map and Data.Set. Don't they fulfill your needs? Don't reimplement, reuse.
OCaml 标准库使用 AVL 树作为其
map
函子。如果包含remove
操作,它似乎比 RB 树更容易实现。The OCaml standard library uses an AVL tree for its
map
functor. It seems as though it's easier to implement than an RB-tree if you include aremove
operation.