Дробное каскадирование - Fractional cascading - Wikipedia

В Информатика, дробное каскадирование это техника для ускорения последовательности бинарный поиск для того же значения в последовательности связанных структур данных. Первый двоичный поиск в последовательности занимает логарифмическое количество времени, что является стандартным для двоичного поиска, но последующие поиски в последовательности выполняются быстрее. Первоначальная версия дробного каскадирования, представленная в двух статьях Chazelle и Гибас в 1986 г. (Шазель и Гибас 1986a; Шазель и Гибас 1986b ), объединил идею каскадирования, возникшую в поиск диапазона структуры данных Люкер (1978) и Уиллард (1978), с идеей дробной выборки, которая зародилась в Шазель (1983). Позднее авторы представили более сложные формы дробного каскадирования, которые позволяют поддерживать структуру данных по мере изменения данных посредством последовательности дискретных событий вставки и удаления.

Пример

В качестве простого примера дробного каскадирования рассмотрим следующую проблему. В качестве входных данных мы получаем набор k упорядоченные списки Lя чисел, таких что общая длина Σ |Lя| всех списков п, и должен обрабатывать их, чтобы мы могли выполнять двоичный поиск значения запроса q в каждом из k списки. Например, с k = 4 и п = 17,

L1 = 24, 64, 65, 80, 93
L2 = 23, 25, 26
L3 = 13, 44, 62, 66
L4 = 11, 35, 46, 79, 81

Самое простое решение этой проблемы поиска - просто хранить каждый список отдельно. Если мы это сделаем, то необходимое место будет O (п), но время выполнения запроса - O (k бревно(п/k)), так как мы должны выполнять отдельный бинарный поиск в каждом из k списки. Наихудший случай запроса этой структуры возникает, когда каждый из k списки имеют одинаковый размер п/k, поэтому каждый из k бинарный поиск, участвующий в запросе, занимает время O (log (п/k)).

Второе решение позволяет выполнять более быстрые запросы за счет большего пространства: мы можем объединить все k списки в один большой список L, и связать с каждым элементом Икс из L список результатов поиска Икс в каждом из меньших списков Lя. Если мы опишем элемент этого объединенного списка как Икс[а,б,c,d] куда Икс - числовое значение и а, б, c, и d позиции (первое число имеет позицию 0) следующего элемента размером не менее Икс в каждом из исходных входных списков (или в позиции после конца списка, если такой элемент не существует), тогда у нас будет

L = 11[0,0,0,0], 13[0,0,0,1], 23[0,0,1,1], 24[0,1,1,1], 25[1,1,1,1], 26[1,2,1,1],
35[1,3,1,1], 44[1,3,1,2], 46[1,3,2,2], 62[1,3,2,3], 64[1,3,3,3], 65[2,3,3,3],
66[3,3,3,3], 79[3,3,4,3], 80[3,3,4,4], 81[4,3,4,4], 93[4,3,4,5]

Это объединенное решение позволяет запрос за время O (журнал п + k): просто найдите q в L а затем сообщить о результатах, хранящихся в элементе Икс найдено с помощью этого поиска. Например, если q = 50, поиск q в L находит элемент 62 [1,3,2,3], из которого мы возвращаем результаты L1[1] = 64, L2[3] (значение флага, указывающее, что q прошел конец L2), L3[2] = 62 и L4[3] = 79. Тем не менее, это решение требует высокой сложности пространства: оно использует пространство O (кн) как каждый из п предметы в L должен хранить список k результаты поиска.

Дробное каскадирование позволяет решить ту же проблему поиска с ограничениями по времени и пространству, которые соответствуют лучшим из обоих миров: время запроса O (log п + k), а пространство O (пРешением дробного каскадирования является сохранение новой последовательности списков. Mя. Последний список в этой последовательности, Mk, равно Lk; каждый предыдущий список Mя образуется путем слияния Lя с каждым вторым предметом из Mя+1. С каждым предметом Икс в этом объединенном списке мы храним два числа: позиция, полученная в результате поиска Икс в Lя и позиция, полученная в результате поиска Икс в Mя+1. Для приведенных выше данных это даст нам следующие списки:

M1 = 24[0, 1], 25[1, 1], 35[1, 3], 64[1, 5], 65[2, 5], 79[3, 5], 80[3, 6], 93[4, 6]
M2 = 23[0, 1], 25[1, 1], 26[2, 1], 35[3, 1], 62[3, 3], 79[3, 5]
M3 = 13[0, 1], 35[1, 1], 44[1, 2], 62[2, 3], 66[3, 3], 79[4, 3]
M4 = 11[0, 0], 35[1, 0], 46[2, 0], 79[3, 0], 81[4, 0]

Предположим, мы хотим выполнить запрос в этой структуре для q = 50. Сначала мы выполняем стандартный двоичный поиск для q в M1, находя значение 64[1,5]. «1» в 64 [1,5] говорит нам, что поиск q в L1 должен вернуться L1[1] = 64. "5" в 64[1,5] говорит нам, что приблизительное местоположение q в M2 это позиция 5. Точнее, двоичный поиск q в M2 вернет либо значение 79 [3,5] в позиции 5, либо значение 62 [3,3] на одну позицию ранее. Сравнивая q до 62 и, заметив, что он меньше, мы определяем, что правильный результат поиска M2 62 [3,3]. Первая цифра «3» в 62 [3,3] говорит нам, что поиск q в L2 должен вернуться L2[3], значение флага, означающее, что q находится за концом списка L2. Вторая цифра «3» в 62 [3,3] говорит нам, что приблизительное местоположение q в M3 это позиция 3. Точнее, двоичный поиск q в M3 вернет либо значение 62 [2,3] в позиции 3, либо значение 44 [1,2] на одну позицию ранее. Сравнение q с меньшим значением 44 показывает нам, что правильный результат поиска в M3 62 [2,3]. «2» в 62 [2,3] говорит нам, что поиск q в L3 должен вернуться L3[2] = 62, а «3» в 62 [2,3] говорит нам, что результат поиска q в M4 либо M4[3] = 79 [3,0] или M4[2] = 46 [2,0]; сравнение q с 46 показывает, что правильный результат - 79 [3,0] и что результат поиска q в L4 является L4[3] = 79. Таким образом, мы нашли q в каждом из наших четырех списков, выполняя двоичный поиск в одном списке M1 с последующим однократным сравнением в каждом из последовательных списков.

В более общем смысле, для любой структуры данных этого типа мы выполняем запрос, выполняя двоичный поиск для q в M1, и определяя по полученному значению положение q в L1. Затем для каждого я > 1, используем известное положение q в Mя найти свое место в Mя+1. Значение, связанное с положением q в Mя указывает на позицию в Mя+1 это либо правильный результат двоичного поиска для q в Mя+1 или находится в одном шаге от правильного результата, поэтому я к я +1 требует только одного сравнения. Таким образом, общее время запроса равно O (log п + k).

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

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

как можно увидеть, перегруппировав вклады в общий размер, поступающие из того же входного списка Lя вместе друг с другом.

Общая проблема

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

Для обработки запросов этого типа для графа, в котором каждая вершина имеет не более d входящие и самое большее d исходящие ребра для некоторой постоянной dсписки, связанные с каждой вершиной, дополняются частью элементов от каждого исходящего соседа вершины; дробь должна быть меньше 1 /d, поэтому общая сумма, на которую расширяются все списки, остается линейной по отношению к размеру ввода. Каждый элемент в каждом расширенном списке сохраняет позицию этого элемента в нерасширенном списке, хранящемся в той же вершине, и в каждом из исходящих соседних списков. В простом примере выше d = 1, и мы увеличили каждый список на 1/2 части соседних элементов.

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

Динамическое дробное каскадирование

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

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

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

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

  • Отображение элементов в расширенном списке узла на небольшие целые числа, так что порядок позиций в расширенном списке эквивалентен порядку сравнения целых чисел, и обратное отображение этих целых чисел обратно в элементы списка. Техника Диц (1982) позволяет эффективно поддерживать эту нумерацию.
  • Целочисленная структура данных поиска, такая как дерево ван Эмде Боас для чисел, связанных с входным списком узла. С помощью этой структуры и преобразования элементов в целые числа можно эффективно найти для каждого элемента Икс расширенного списка, элемент, который будет найден при поиске Икс в списке ввода.
  • Для каждого соседнего узла в графе каталога аналогичная целочисленная структура данных поиска для чисел, связанных с подмножеством данных, распространяемых из соседнего узла. С помощью этой структуры и преобразования элементов в целые числа можно эффективно найти для каждого элемента Икс расширенного списка, позиция в пределах постоянного числа шагов расположения Икс в расширенном списке, связанном с соседним узлом.

Эти структуры данных позволяют выполнять динамическое дробное каскадирование за время O (logп) на вставку или удаление, а последовательность k бинарный поиск по пути длины k в графе каталога, которое должно быть выполнено за время O (logп + k журнал журналп).

Приложения

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

Типичные применения дробного каскадирования включают: поиск по диапазону структуры данных в вычислительная геометрия. Например, рассмотрим проблему полуплоскость отчет о диапазоне: то есть пересечение фиксированного набора п указывает с запросом полуплоскость и перечислить все точки пересечения. Проблема состоит в том, чтобы структурировать точки таким образом, чтобы на запрос этого типа можно было эффективно ответить с точки зрения размера пересечения. час. Одной из структур, которые можно использовать для этой цели, является выпуклые слои набора входных точек, семейство вложенных выпуклые многоугольники состоящий из выпуклый корпус множества точек и рекурсивно построенных выпуклых слоев остальных точек. Внутри одного слоя точки внутри полуплоскости запроса могут быть найдены путем выполнения двоичного поиска наклона граничной линии полуплоскости среди отсортированной последовательности наклонов выпуклых краев многоугольника, ведущей к вершине многоугольника, которая находится внутри половины запроса -плоскости и дальше всего от ее границы, а затем последовательный поиск вдоль ребер многоугольника, чтобы найти все остальные вершины внутри полуплоскости запроса. Проблема сообщения о диапазоне в целом в полуплоскости может быть решена путем повторения этой процедуры поиска, начиная с самого внешнего уровня и продолжаясь внутрь до достижения уровня, который не пересекается с полупространством запроса. Дробное каскадирование ускоряет последовательные бинарные поиски среди последовательностей наклонов краев многоугольника в каждом слое, что приводит к структуре данных для этой проблемы с пространством O (п) и время запроса O (журналп + час). Структура данных может быть построена за время O (п бревноп) по алгоритму Шазель (1985). Как и в нашем примере, это приложение включает двоичный поиск в линейной последовательности списков (вложенная последовательность выпуклых слоев), поэтому граф каталога представляет собой просто путь.

Другое применение дробного каскадирования в геометрических структурах данных касается точка расположения в монотонном подразделении, то есть в таком разбиении плоскости на многоугольники, что любая вертикальная линия пересекает любой многоугольник не более чем в двух точках. В качестве Эдельсбруннер, Гибас и Стольфи (1986) Как было показано, эта проблема может быть решена путем нахождения последовательности многоугольных путей, которые проходят слева направо через подразделение, и двоичного поиска самого нижнего из этих путей, который находится выше точки запроса. Проверка того, находится ли точка запроса выше или ниже одного из путей, сама по себе может быть решена как проблема двоичного поиска, поиск координаты x точек среди координат x вершин пути, чтобы определить, какое ребро пути может быть выше или ниже точка запроса. Таким образом, каждый запрос местоположения точки может быть решен как внешний уровень двоичного поиска среди путей, каждый шаг которого сам выполняет двоичный поиск среди x координат вершин. Дробное каскадирование можно использовать для ускорения внутреннего двоичного поиска, уменьшая общее время запроса до O (logп) с использованием структуры данных с пробелом O (п). В этом приложении граф каталога представляет собой дерево, представляющее возможные последовательности поиска внешнего двоичного поиска.

Помимо вычислительной геометрии, Лакшман и Стилиадис (1998) и Буддхикот, Сури и Вальдфогель (1999) применять дробное каскадирование при проектировании структур данных для быстрого фильтрация пакетов в интернет-маршрутизаторы. Gao et al. (2004) использовать дробное каскадирование в качестве модели для распределения и поиска данных в сенсорные сети.

Рекомендации