与此问题相关,基于用户Eric Lippert的评论。
是否存在绳索数据结构比字符串生成器更有效的情况?有些人认为,rope 数据结构在速度方面几乎永远不会比典型情况下的本地字符串或字符串构建器操作更好,所以我很想看到绳索确实更好的现实场景。
与此问题相关,基于用户Eric Lippert的评论。
是否存在绳索数据结构比字符串生成器更有效的情况?有些人认为,rope 数据结构在速度方面几乎永远不会比典型情况下的本地字符串或字符串构建器操作更好,所以我很想看到绳索确实更好的现实场景。
SGI C++ 实现的文档详细介绍了大 O 行为与具有启发性的常量因素。
他们的文档假设涉及非常长的字符串,作为参考的示例讨论了10 MB 的字符串。很少会编写处理此类事情的程序,并且对于具有此类要求的许多类别的问题,将它们重新设计为基于流而不是要求在可能的情况下提供完整的字符串将导致显着优越的结果。因此,当您能够适当地将绳索视为部分(它们本身是绳索)而不仅仅是字符序列时,此类绳索用于多兆字节字符序列的非流式处理。
显着优点:
显着缺点:
这导致了一些“明显”的用途(SGI 明确提到的第一个用途)。
在某些情况下,字符串中的特定领域行为可以与对 Rope 实现的相对简单的扩充相结合,以允许:
正如您从列出的示例中看到的那样,所有这些都属于“利基”类别。此外,如果您愿意/能够将算法重写为流处理操作,那么一些可能会有更好的选择。
这个问题的简短回答是肯定的,这几乎不需要解释。当然,在某些情况下,绳索数据结构比字符串生成器更有效。它们的工作方式不同,因此它们更适合不同的目的。
(从 C# 的角度来看)
作为二叉树的绳索数据结构在某些情况下更好。当您查看非常大的字符串值时(想想 100+ MB 来自 SQL 的 xml),绳索数据结构可以使整个过程远离大对象堆,当字符串对象通过 85000 字节时,它会在其中命中它。
如果您正在查看 5-1000 个字符的字符串,它可能不会提高性能,以至于值得。这是另一种数据结构的例子,它是为 5% 处于极端情况的人设计的。
第10 届 ICFP 编程竞赛基本上 依靠人们使用绳索数据结构进行有效解决。这是获得在合理时间内运行的 VM 的大技巧。
如果有很多前缀(显然“前缀”这个词是由 IT 人员编造的,不是一个合适的词!),绳子就非常好,并且可能更适合插入;StringBuilders 使用连续内存,因此只能有效地进行追加。
因此,StringBuilder 非常适合通过附加片段来构建字符串——这是一个非常正常的用例。由于开发人员需要做很多事情,StringBuilders 是一种非常主流的技术。
绳索非常适合编辑缓冲区,例如,企业级 TextArea 背后的数据结构。所以(绳索的放松,例如线的链表而不是二叉树)在 UI 控件世界中很常见,但这些控件的开发人员和用户并不经常公开。
您需要非常大量的数据和流失才能获得回报 - 处理器非常擅长流操作,如果您有 RAM,那么简单地重新分配前缀对于正常用例来说确实可以接受。顶部提到的那场比赛是我唯一一次看到它需要。
大多数高级文本编辑器将文本主体表示为“一种绳索”(尽管在实现中,叶子通常不是单个字符,而是文本运行),主要是为了改善对大文本的频繁插入和删除。
通常,StringBuilder 针对追加进行了优化,并尝试在不过度分配的情况下尽量减少重新分配的总数。典型的保证是(log2 N 分配,小于 2.5 倍的内存)。通常字符串会被构建一次,然后可以使用很长一段时间而不被修改。
Rope 针对频繁的插入和删除进行了优化,并尝试最小化复制的数据量(通过大量分配)。在线性缓冲区实现中,每次插入和删除都变成 O(N),并且您通常必须表示单个字符的插入。
Javascript VM 经常使用绳索作为字符串。
Higgs Javascript VM 的开发者 Maxime Chevalier-Boisvert说:
在 JavaScript 中,您可以使用字符串数组并最终使用 Array.prototype.join 来相当快地进行字符串连接,O(n),但是 JS 程序员倾向于构建字符串的“自然”方式是使用 += 运算符附加到逐步构建它们。JS 字符串是不可变的,所以如果内部没有优化,增量追加是 O(n2)。我认为绳索很可能是在 JS 引擎中实现的,特别是因为 SunSpider 基准执行字符串附加。JS 引擎实现者使用绳索通过使以前速度较慢的东西变得更快来获得优于其他人的优势。如果不是这些基准测试,我认为社区中关于字符串附加性能不佳的呼声可能会遇到“使用 Array.prototype.join,dummy!”。
也。