В компьютерном программировании развернутый связанный список - это вариант связанного списка, в котором хранится несколько элементов в каждом узле. Это может значительно увеличить производительность кэша , одновременно уменьшив накладные расходы памяти, связанные с хранением метаданных списка, таких как ссылки. Это связано с B-деревом.
Типичный узел развернутого связанного списка выглядит так:
record node {node next // ссылка на следующий узел в списке int numElements // количество элементов в этом узле, вплоть до элементов массива maxElements // массив элементов numElements, // с пространством, выделенным для элементов maxElements}
Каждый узел вмещает до определенного максимального количества элементов, обычно достаточно большого, чтобы узел заполнял единственный кеш строка или кратное ей меньшее. Позиция в списке обозначается как ссылкой на узел, так и позицией в массиве элементов. Также можно включить предыдущий указатель для развернутого двусвязного списка.
Чтобы вставить новый элемент, мы просто находим узел, в котором должен находиться элемент, и вставляем элемент в элементы
массив, увеличивающий numElements
. Если массив уже заполнен, мы сначала вставляем новый узел, предшествующий или следующий за текущим, и перемещаем в него половину элементов текущего узла.
Чтобы удалить элемент, мы просто находим узел, в котором он находится, и удаляем его из массива elements
, уменьшая numElements
. Если это уменьшает узел до менее чем наполовину полного, мы перемещаем элементы из следующего узла, чтобы заполнить его снова выше половины. Если в результате следующий узел остается заполненным менее чем наполовину, мы перемещаем все его оставшиеся элементы в текущий узел, затем пропускаем и удаляем его.
Одним из основных преимуществ развернутых связанных списков является уменьшение требований к хранилищу. Все узлы (кроме одного) заполнены как минимум наполовину. Если выполняется много случайных вставок и удалений, средний узел будет заполнен примерно на три четверти, а если вставки и удаления выполняются только в начале и в конце, почти все узлы будут заполнены. Предположим, что:
maxElements
, максимальное количество элементов в каждом elements
array ;Тогда пространство, используемое для n элементов, варьируется в пределах и . Для сравнения, обычные связанные списки требуют пробела, хотя v может быть меньше, а массивов - один Для наиболее компактных структур данных требуется пробел. Развернутые связанные списки эффективно распределяют накладные расходы v на несколько элементов списка. Таким образом, мы видим наиболее значительный прирост пространства, когда накладные расходы велики, maxElements
велико, или элементы маленькие.
Если элементы особенно малы, например биты, накладные расходы могут быть в 64 раза больше, чем данные на многих машинах. Более того, многие популярные распределители памяти будут хранить небольшой объем метаданных для каждого выделенного узла, увеличивая эффективные накладные расходы v. Оба эти фактора делают развернутые связанные списки более привлекательными.
Поскольку каждый узел развернутого связанного списка хранит счетчик рядом со следующим полем, получение k-го элемента развернутого связанного списка (индексация) может выполняться за n / m + 1 промахов в кэш с коэффициентом м лучше обычных связанных списков. Кроме того, если размер каждого элемента мал по сравнению с размером строки кэша, список может быть перемещен в порядке с меньшим количеством промахов в кэше, чем обычные связанные списки. В любом случае время операции по-прежнему линейно увеличивается с размером списка.