LINUX.ORG.RU
ФорумTalks

Новая структура данных Black-White Array

 


0

2

https://habr.com/ru/articles/984184/

Github

Преимущества

  • Амортизированное время вставки/удаления/поиска O(\log N) - сравнимое с BTree от Google;
  • Количество аллокаций памяти при операциях вставки так же O(\log N) - меньше давления на сборщик мусора, ниже фрагментация памяти;
  • Массивы под капотом: данные лежат рядом, что улучшает кэшируемость процессором и скорость обхода/доступа к данным;
  • Позволяет хранить элементы с одинаковыми ключами - не нужно использовать дополнительные структуры для группировки таких элементов;
  • Низкий оверхед на хранение служебной информации - экономия памяти по сравнению с другими структурами данных;
  • Удобен для вставки батчами;
  • Простая сериализация и десериализация;

Компромиссы

  • Время вставки варьируется от O(1) - каждая вторая вставка, до O(N) - один раз на N операций, но амортизированное время O(\log N). Для near-real-time систем это может быть критично. Эффект может быть нивелирован вставкой батчами, или асинхронной вставкой в фоне.

  • При редких паттернах операций массового удаления, возможна деградация производительности поиска до O(N)/4. Эффект может быть предотвращен вызовом метода Compact().

Пора делать новую ФС на новом принципе.

★★★★★

Последнее исправление: ptah_alexs (всего исправлений: 1)
Ответ на: комментарий от dataman

Ага, забыл на репу ссылку написать. Добавил.

ptah_alexs ★★★★★
() автор топика
Ответ на: комментарий от u-235

Название не толерантное, не взлетит.

Если ты про негров то их нельзя называть именно неграми, а вот черными можно.

Ygor ★★★★★
()
Ответ на: комментарий от Ygor

Я про то, что и глазом не моргнёшь, как белые ячейки массива начнут угнетать черные.

u-235
()
Ответ на: комментарий от Ygor

Если ты про негров то их нельзя называть именно неграми, а вот черными можно.

blacklist/whitelist всякие комитеты по этосамому рекомендуют заменять на blocklist/allowlist

нельзя называть именно неграми

Наш «негр» переводится negro, а нельзя nigger

goingUp ★★★★★
()

сравнимое с BTree от Google

Что за гуглофанатизм? btree никаким боком не от гугла,

И вообще, чем описанное отличается от btree по характеристикам? По ссылке не ходил.

Сдаётся мне что там никакая не новая структура а чья-то очередная курсовая работа по реализации какого-то баяна.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Да ты и пост не читал. Меньше памяти занимает, внутри массивы, следовательно, меньше обращений вне кэша проца, вставка, удаление на уровне b-tree.

ptah_alexs ★★★★★
() автор топика
Ответ на: комментарий от ptah_alexs

Внутри btree тоже массивы можно сделать, если тебе не требуется переменная длина элементов. И памяти он занимает очень даже мало.

firkax ★★★★★
()
Ответ на: комментарий от dataman

Ладно, сходил по ссылке.

И правда что-то разумное.

Тогда вопрос к автору: зачем было тащить сюда всякую болтовню для нубов вместо описания алгоритма?

firkax ★★★★★
()
Ответ на: комментарий от firkax

Мне лень, кроме того Ъ должны страдать.

ptah_alexs ★★★★★
() автор топика

Простая сериализация и десериализация;

Не раскрыто, и заголовков струтур не видно при прочтении по-диагонали. Мне кажется это могло бы быть ключевой фишкой, типа zero-copy передача kv по всяким shared memory между процессами так, чтобы формат данных описывался как стандарт просто, без привязки к алгоритму.

snizovtsev ★★★★★
()
Последнее исправление: snizovtsev (всего исправлений: 3)
Ответ на: комментарий от Bfgeshka

Описание я уже нашёл, возражение касалось того что автор этой темы его прям тут не расписал что б не ходить по ссылкам.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ну вообще хорошо бы расписать хотя бы общий принцип, а не только алгоритмическую сложность операций. Да и структура данных не шибко новая - исследование ещё в 2020 вышло.

Опуская детали, принцип в том, чтобы иметь чёрный массив емкостью в половину основного белого и использовать его для выполнения операций. Сами массивы состоят из сегментов размером pot. С таким подходом можно избежать временных аллокаций памяти для выполнения штатных операций.

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

Опуская детали, принцип в том, чтобы иметь чёрный массив емкостью в половину основного белого и использовать его для выполнения операций.

Ты, почти как автор темы, опустил самое важное.

Напишу тогда свой пересказ:

=== описание хранения данных ===

Экземпляр описываемой «структуры» как цельный объект (т.е. всё ниженаписанное - описание внутреннего устройства одного экземпляра) буду называть bwarr.

Данные хранятся массиве, нарезанном на фрагменты, размер каждого из которых равен pow(2,n), где n - номер фрагмента, нумерация начинается с нуля. Запишем так: frag[n] - n-ный фрагмент, frag[n][m] - m-ый элемент n-го фрагмента, при этом n>=0, 0<=m<pow(2,n). Если нужна поддержка операции удаления, то frag[n][m] должен уметь хранить как элемент, так и признак «тут ничего нет». Если не нужна, то признак пустоты нужен только фрагментам целиком, но не отдельным их элементам.

Консистентное состояние данных выглядит так: каждый из фрагментов, независимо от остальных, хранит отсортированное подмножество ранее добавленных в bwarr элементов. Чем больше номер фрагмента - тем более старые элементы в нём хранятся, то есть фрагменты, можно считать, отсортированы по времени добавления содержащихся в них элементов, но при этом сами элементы внутри одного фрагмента отсортированы по требуемому сортирующему признаку. Фрагмент может быть либо пустым (в нём нет ни одного элемента), либо содержать k элементов такое, что pow(2,n-1)<k<=pow(2,n). То есть, любой непустой фрагмент всегда заполнен более чем наполовину. Таким образом, если в bwarr ровно N=pow(2,X) элементов (X=log_2(N)), то они либо все хранятся в frag[X], либо часть из них (все не влезут) хранится в более нижних фрагментах (причём не все варианты расположения возможны). Если элементов меньше чем pow(2,X) то фрагменты с номерами больше X всё так же не могут быть непустыми.

=== описание операции поиска ===

Поиск ведётся параллельно во всех непустых фрагментах. Поскольку максимальный номер непустого фрагмента зависит от общего количества элементов N, параллельно искать придётся не более чем в ceil(log_2(N))+1 = X+1 фрагментах. Сам поиск по заранее отсортированным фрагментам делается за логарифмическое от их размера pow(2,n) (и соответственно линейное от их номера n) количество операций. Если сложить эту арифметическую прогрессию, получаем сложность поиска приблизительно пропорциональную sqr(X) = sqr(log_2(N)).

=== описание операций изменения данных ===

Для вставки и иногда для удаления используется временный буфер (почему-то там его назвали чёрным массивом), требуемый размер этого буфера равен размеру последнего из разрешённых/планируемых к использованию фрагментов (если не нужно удаление, размер временного буфера можно сделать меньше на 25%).

Вставка делается так: если frag[0] пустой, просто кладём элемент в него и завершаемся, иначе кладём вставляемый элемент во временный буфер, ставим счётчик i=0, и затем выполняем в цикле следующее:

  • Делаем отсортированное слияние frag[i] и временного буфера. frag[i] после этого объявляем пустым (все элементы из него переехали в слияние). При этом, если frag[i+1] пустой, результат пишется в него и завершаемся. Иначе - результат пишется во временный буфер, счётчик i инкрементируется, идём на следующий цикл.

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

Удаление делается так: элемент (после поиска) просто помечается как пустой. Затем делается проверка: если в фрагмент до сих пор заполнен больше чем на половину (т.е. пустых мест меньше половины) - завершаемся. Если пустых мест теперь половина, а предыдущий фрагмент пустой - переносим элементы туда. Если пустых мест половина, а предыдущий фрагмент не пустой - производим сортированное слияние с ним (через временный буфер), после чего записываем результат на место текущего фрагмента (а предыдущий, из которого мы забрали элементы, объявляем пустым).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 3)
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)