Сортировать Гильберта по алгоритму разделяй и властвуй? - PullRequest
20 голосов
/ 11 декабря 2011

Я пытаюсь отсортировать d-мерные векторы данных по их порядку Гильберта для массовой загрузки пространственного индекса.

Однако я не хочу явно вычислять значение Гильберта для каждой точки, чтов частности требует установки определенной точности.В многомерных данных это включает в себя точность, такую ​​как 32*d бит, которая становится довольно грязной, чтобы делать это эффективно.Когда данные распределяются неравномерно, некоторые из этих вычислений не нужны, и необходима дополнительная точность для частей набора данных.

Вместо этого я пытаюсь использовать подход разделения.Когда вы посмотрите на двумерную гильбертову кривую первого порядка

1   4
|   |
2---3

, я сначала разделю данные вдоль оси x, так что первая часть (необязательно содержащая половину объектов!) Будет состоять из1 и 2 (еще не отсортированы), а во второй части будут только объекты от 3 и 4.Затем я бы снова разделил каждую половину по оси Y, но изменил бы порядок на 3-4.

Итак, по сути, я хочу реализовать стратегию «разделяй и властвуй» (тесно связанную с QuickSort -для равномерно распределенных данных это должно быть даже оптимально!) и вычислять только необходимые «биты» индекса Гильберта по мере необходимости.Таким образом, если предположить, что в «1» есть один объект, тогда нет необходимости вычислять его полное представление;и если объекты распределены равномерно, размеры разделов быстро уменьшатся.

Я знаю обычный учебный подход, заключающийся в преобразовании в длинное с серым кодированием чередование измерений.Это не то, что я ищу (существует множество примеров этого).Я явно хочу ленивый разделяй и властвуй сортировка только 1015 *.Кроме того, мне нужно больше, чем 2D.

Кто-нибудь знает статью или алгоритм гильбертовой сортировки, который работает таким образом?Или ключевая идея, как правильно "вращать", какое представление выбрать для этого?В частности, в более высоких измерениях ... в 2D это тривиально;1 поворачивается + y, + x, а 4 - -y, -x (поворачивается и переворачивается).Но в более высоких измерениях это становится более сложным, я думаю.

(Результат, конечно, должен быть таким же, как и при сортировке объектов по их порядку Гильберта с достаточно большой точностью сразу; я просто пытаюсьсэкономьте время, вычисляя полное представление, когда оно не нужно, и управляя им. Многие люди хранят хэш-карту «число Гильберта», которая является довольно дорогой.)

Подобные подходы должны быть возможны для кривых Пеано и Z-curve, и, возможно, немного проще в реализации ... Я, вероятно, должен сначала попробовать это (Z-кривая уже работает - она ​​действительно сводится к чему-то, очень похожему на QuickSort, используя соответствующее среднее значение / значение сетки в качестве виртуального центра и цикларазмеры для каждой итерации).

Редактировать : см. ниже, как я решил это для Z и кривых Пеано.Это также работает для 2D кривых Гильберта.Но у меня пока нет правильных поворотов и инверсий для кривых Гильберта.

Ответы [ 3 ]

7 голосов
/ 13 декабря 2011

Используйте radix sort . Разделите каждый одномерный индекс на d .. 32 части, каждая размером 1 .. 32/d бит. Затем (от старших разрядов до младших разрядов) для каждого элемента индекса вычисляют его значение Гильберта и перетасовывают объекты в соответствующие ячейки.

Это должно хорошо работать как с равномерно, так и с неравномерно распределенными данными, как в порядке Гильберта, так и в Z-порядке И нет необходимости в многоточечных вычислениях.

Одна деталь о преобразовании частей индекса в порядок Гильберта:

  • сначала извлечь необходимые биты,
  • затем чередовать биты из всех измерений,
  • затем преобразуйте одномерные индексы в обратный код Грея.

Если индексы хранятся в двойных числах:

  • Если индексы могут быть отрицательными, добавьте некоторое значение, чтобы сделать все положительным и, таким образом, упростить задачу.
  • Определите наименьшую целую степень 2, которая больше всех индексов, и разделите все индексы на это значение
  • Умножьте индекс на 2 ^ (необходимое количество бит для текущего шага сортировки). Усечение результата, преобразование его в целое число и использование его для упорядочения Гильберта (чередование и вычисление обратного кода Грея)
  • Вычтите результат, усеченный на предыдущем шаге, из индекса: index = index - i

Что касается вашего варианта радикальной сортировки, я бы предложил расширить zsort (чтобы сделать hilbertsort из zsort) двумя двоичными массивами размером d (один используется в основном как стек, другой используется для инвертирования битов индекса ) и значение поворота (используется для изменения размеров).

Если верхнее значение в стеке равно 1, измените pivotize (... восходящий) на pivotize (... нисходящий), а затем для первой части рекурсии перенесите это верхнее значение в стек для второго - нажмите обратное значение этого значения. Этот стек следует восстанавливать после каждой рекурсии. Он содержит «дерево решений» последних d рекурсий процедуры сортировки по основанию (в обратном коде Грея).

После d рекурсий этот стек "дерева решений" должен использоваться для пересчета как значения вращения, так и массива инверсий. Точный способ, как это сделать, нетривиален. Его можно найти по следующим ссылкам: hilbert.c или hilbert.c .

2 голосов
/ 13 декабря 2011

Вы можете вычислить кривую Гильберта из f (x) = y напрямую, без использования рекурсии или L-систем, или «разделяй и властвуй».В основном это серый код или обход гамильтоновых путей.Вы можете найти хорошее описание в блоге Nad, посвященном пространственному индексу Гильберта Кривой, или в восторге от книги хакера.Или взгляните на монотонный н-арый серый код.Я написал реализацию в php, включая кривую Мура.

0 голосов
/ 29 марта 2012

Я уже ответил на этот (и другие) вопрос, но мои ответы загадочным образом исчезли.Реализация компактного индекса Гильберта из http://code.google.com/p/uzaygezen/source/browse/trunk/core/src/main/java/com/google/uzaygezen/core/CompactHilbertCurve.java (индекс метода ()) уже позволяет ограничить число битов индекса Гильберта, вычисляемых до заданного уровня.Каждая итерация цикла из упомянутого метода вычисляет количество бит, равное размерности пространства.Вы можете легко реорганизовать цикл for для вычисления только одного уровня (т. Е. Числа бит, равного размерности пространства) за раз, делая это настолько глубоко, насколько необходимо для сравнения лексикографически двух чисел по их компактному индексу Гильберта.

...