Есть ли какой-либо сценарий, в котором структура данных Rope более эффективна, чем построитель строк?

Относится к этому вопросу на основе комментария пользователя Эрик Липперт.

Есть ли сценарий, при котором структура данных Rope более эффективна, чем построитель струн? Некоторые люди считают, что в типичных случаях веревочные структуры данных почти никогда не бывают лучше по скорости, чем нативные строки или операции построения строк, поэтому мне любопытно увидеть реалистичные сценарии, в которых веревки действительно лучше.


person luvieere    schedule 07.12.2009    source источник
comment
По общему признанию, мой опыт ограничен; Я пытался добавить строковые представления в стиле веревки к таким языкам, как VBScript и JScript. Количество случаев, в которых мы должны агрессивно преобразовывать внутренние строки в реальные строки на основе буфера, было настолько большим, а количество случаев, когда операции со строками во время выполнения действительно становились большими, сложными строками было настолько мало, что влияние на чистую производительность было отрицательным. Когда мы строили строковую логику в JScript.NET, мы просто использовали конструктор строк, вместо того, чтобы снова пытаться связать веревки.   -  person Eric Lippert    schedule 08.12.2009
comment
Возможно, одна из областей, где веревка будет работать лучше, будет сценарием, в котором поиск будет преобладать над другими операциями, поэтому веревочное представление неструктурированного текста, который требует частого поиска, было бы адекватным, не так ли?   -  person luvieere    schedule 08.12.2009
comment
luvieere, поиск будет медленнее.   -  person Henk Holterman    schedule 08.12.2009
comment
Почему это так, учитывая, что подстрока быстрее?   -  person luvieere    schedule 08.12.2009
comment
Извлечение подстроки из заданной позиции и поиск в строке соответствующей подстроки - это совершенно разные операции.   -  person Eric Lippert    schedule 08.12.2009
comment
Поиск подстроки среди двоичного дерева частичных строк звучит как нечто, что я бы не хотел реализовывать.   -  person James Dunne    schedule 08.12.2009
comment
Карл-Фридрих Больц реализовал веревки для Pypy, он сказал мне, что, за исключением тщательно подобранных тестов, ни один из реальных сценариев не показал улучшения. Однако он догадывался, что трудно найти код, который лучше работал бы с веревками, потому что весь существующий код написан с учетом характеристик производительности строк.   -  person akuhn    schedule 08.12.2009
comment
Цитируя источник ссылки, в .Net 4.0+ StringBuilder внутренне представлен как связанный список блоков, каждый из которых содержит кусок строки.   -  person Brian    schedule 09.04.2015


Ответы (5)


Документация для реализации SGI C ++ содержит некоторые подробности по стихам о большом поведении O постоянные факторы, что поучительно.

Их документация предполагает использование очень длинных строк, а примеры, приведенные для справки, говорят о строках размером 10 МБ. Будет написано очень мало программ, которые имеют дело с такими вещами, и для многих классов проблем с такими требованиями их переработка, чтобы они были основаны на потоках, вместо того, чтобы требовать, чтобы полная строка была доступна, где это возможно, приведет к значительно лучшему полученные результаты. Поскольку такие веревки предназначены для непотокового манипулирования многомегабайтными последовательностями символов, когда вы можете надлежащим образом рассматривать веревку как секции (сами веревки), а не просто последовательность символов.

Существенные плюсы:

  • Конкатенация / вставка становятся операциями с почти постоянным временем
  • Certain operations may reuse the previous rope sections to allow sharing in memory.
    • Note that .Net strings, unlike java strings do not share the character buffer on substrings - a choice with pros and cons in terms of memory footprint. Ropes tend to avoid this sort of issue.
  • Ropes allow deferred loading of substrings until required
    • Note that this is hard to get right, very easy to render pointless due to excessive eagerness of access and requires consuming code to treat it as a rope, not as a sequence of characters.

Существенные минусы:

  • Случайный доступ для чтения становится O (log n)
  • Постоянные коэффициенты при последовательном доступе для чтения составляют от 5 до 10.
  • для эффективного использования API требуется обращаться с ним как с веревкой, а не просто опускать веревку как вспомогательную реализацию на «нормальном» строковом API.

Это приводит к нескольким «очевидным» применениям (первое явно упоминается SGI).

  • Edit buffers on large files allowing easy undo/redo
    • Note that, at some point you may need to write the changes to disk, involving streaming through the entire string, so this is only useful if most edits will primarily reside in memory rather than requiring frequent persistence (say through an autosave function)
  • Манипуляции с сегментами ДНК, где происходят значительные манипуляции, но на самом деле происходит очень мало результатов
  • Многопоточные алгоритмы, которые изменяют локальные части строки. Теоретически такие случаи можно разделить на отдельные потоки и ядра без необходимости брать локальные копии подсекций и затем их рекомбинировать, что экономит значительную часть памяти, а также позволяет избежать дорогостоящей операции последовательного объединения в конце.

Бывают случаи, когда поведение строки, зависящее от предметной области, может быть связано с относительно простыми дополнениями к реализации Rope, что позволяет:

  • Строки только для чтения со значительным количеством общих подстрок поддаются простому интернированию для значительной экономии памяти.
  • Строки с разреженными структурами или значительным локальным повторением поддаются кодированию длин серий, при этом обеспечивая разумные уровни произвольного доступа.
  • Если границы подстроки сами являются «узлами», где может храниться информация, хотя такие структуры вполне возможно, лучше сделать как Radix Trie, если они редко изменяются, но часто читаются.

Как видно из приведенных примеров, все они хорошо попадают в категорию «нишевых». Кроме того, некоторые из них могут иметь превосходные альтернативы, если вы желаете / можете вместо этого переписать алгоритм как операцию обработки потока.

person ShuggyCoUk    schedule 14.12.2009
comment
Что вы думаете об идее использования массива массивов для хранения строк, где каждый промежуточный массив обычно имеет длину в определенном диапазоне (возможно, 256-1023 символа)? Это устранило бы большую часть накладных расходов lg (N) на веревки, но все же уменьшило бы в 30-60 раз стоимость копирования больших частей строки [конкатенация строк часто требовала создания нового объекта последовательности символов для удержания конкатенации последнего сегмента одной строки и первого сегмента другой, но для больших строк это все равно будет дешевле, чем копирование всего. - person supercat; 11.09.2015
comment
@supercat: если сегменты имеют переменную длину, вы получаете индексирование O (N), если они имеют одинаковую длину, вы получаете C ++ std :: deque, который является конкатенацией O (N). - person Yakov Galka; 08.01.2016
comment
@ybungalobill: если структура данных содержит начальное смещение для каждого сегмента, единственной случайной операцией индексации будет o (lgN). Конкатенация потребует перестройки основной структуры, которая будет O (N), но с гораздо меньшей константой, чем с линейной строкой. Поиск индекса рядом с недавно найденным будет O (lg (d)), где d - расстояние между недавно найденным и желаемым. - person supercat; 09.01.2016

краткий ответ на этот вопрос - да, и это требует небольшого объяснения. Конечно, есть ситуации, когда структура данных Rope более эффективна, чем построитель строк. они работают по-разному, поэтому больше подходят для разных целей.

(С точки зрения C #)

Структура данных веревки в виде двоичного дерева лучше в определенных ситуациях. Когда вы смотрите на чрезвычайно большие строковые значения (подумайте, что 100+ МБ xml, поступающего из SQL), структура данных веревки может удерживать весь процесс за пределами кучи больших объектов, где строковый объект попадает в него, когда он передает 85000 байт.

Если вы смотрите на строки из 5-1000 символов, это, вероятно, не улучшает производительность настолько, чтобы того стоило. это еще один случай структуры данных, предназначенной для 5% людей, попавших в экстремальную ситуацию.

person SamuelWarren    schedule 08.12.2009

10-й конкурс программирования ICFP полагался на людей, использующих структура данных веревки для эффективного решения. Это был большой трюк, позволяющий получить виртуальную машину, работающую в разумные сроки.

Веревка отлично подходит, если есть много префиксов (очевидно, слово «добавление» придумано ИТ-специалистами и не является подходящим словом!) И потенциально лучше для вставок; StringBuilders используют непрерывную память, поэтому эффективно работают только при добавлении.

Следовательно, StringBuilder отлично подходит для построения строк путем добавления фрагментов - очень нормальный вариант использования. Поскольку разработчикам требуется много делать это, StringBuilders - очень распространенная технология.

Веревки отлично подходят для буферов редактирования, например. структура данных, лежащая в основе, скажем, TextArea корпоративного уровня. Таким образом (ослабление Ropes, например, связанный список строк, а не двоичное дерево) очень распространено в мире элементов управления пользовательского интерфейса, но это не часто предоставляется разработчикам и пользователям этих элементов управления.

Вам нужны действительно большие объемы данных и отток, чтобы окупиться - процессоры очень хороши в потоковых операциях, и если у вас есть оперативная память, тогда просто перераспределение для префикса работает приемлемо для обычных случаев использования. Это соревнование, упомянутое наверху, было единственным разом, когда я видел, что это нужно.

person Will    schedule 10.12.2009
comment
Когда я участвовал в этом соревновании, я не знал о веревке - поэтому я придумал свое собственное решение: поскольку построители строк отлично подходят для добавления, а поскольку проблема заключалась в префиксе, я просто сохранил свою строку ... в обратном порядке. Шикарно как-то :) - person Will; 11.12.2009

Большинство продвинутых текстовых редакторов представляют тело текста как «своего рода веревку» (хотя в реализации листья обычно не являются отдельными символами, а являются бегущими по тексту), главным образом для улучшения частых вставок и удалений больших текстов.

Как правило, StringBuilder оптимизирован для добавления и пытается минимизировать общее количество перераспределений без чрезмерного превышения доступности. Типичная гарантия составляет (log2 N выделений и меньше 2,5-кратного объема памяти). Обычно строка создается один раз, а затем может использоваться некоторое время без изменения.

Rope оптимизирован для частых вставок и удалений и пытается минимизировать объем копируемых данных (за счет большего количества выделений). В реализации линейного буфера каждая вставка и удаление становится O (N), и вам обычно приходится представлять вставки одного символа.

person peterchen    schedule 14.12.2009

Виртуальные машины Javascript часто используют веревки для строк.

Как сообщает , Максим Шевалье-Буазверт, разработчик виртуальной машины на основе Javascript Хиггса. :

В JavaScript вы можете использовать массивы строк и, в конечном итоге, Array.prototype.join, чтобы сделать конкатенацию строк достаточно быстрой, O (n), но «естественный» способ, которым программисты JS создают строки, - это просто добавить с помощью оператора + = к постепенно создавайте их. Строки JS неизменяемы, поэтому, если это не оптимизировано изнутри, инкрементное добавление составляет O (n2). Я думаю, что вполне вероятно, что веревки были реализованы в JS-движках именно из-за тестов SunSpider, которые выполняют добавление строк. Разработчики движка JS использовали веревки, чтобы получить преимущество над другими, сделав то, что раньше было медленным, быстрее. Если бы не эти тесты, я думаю, что крики сообщества о плохой работе добавления строк могли быть встречены словами «используйте Array.prototype.join, dummy!».

Также < / а>.

person Will    schedule 15.11.2014