Подтвердить что ты не робот

Гильберта сортировать по алгоритму разделения и покорения?

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

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

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

1   4
|   |
2---3

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

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

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

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

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

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

Изменить: см. ниже, как я решил это для кривых Z и peano. Он также работает для 2D кривых Гильберта. Но у меня еще нет поворотов и инверсии для кривых Гильберта.

4b9b3361

Ответ 1

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

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

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

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

Если индексы хранятся в двухлокальных номерах:

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

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

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

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

Ответ 2

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

Ответ 3

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