Я ищу алгоритм постоянного времени, который может изменить значение упорядоченного целочисленного индекса на случайный хеш-индекс. Было бы неплохо, если бы он был обратимым. Мне нужно, чтобы хеш-ключ был уникальным для каждого индекса. Я знаю, что это можно сделать, просмотрев таблицу в большом файле. I.E. создать упорядоченный набор всех целых чисел, а затем перемешать их случайным образом и записать в файл в случайной последовательности. Затем вы можете прочитать их, когда они вам понадобятся. Но для этого потребуется поиск в большом файле. Интересно, есть ли простой способ использовать, скажем, псевдослучайный генератор для создания последовательности по мере необходимости?

Генерация перемешанного диапазона с использованием ГПСЧ вместо перемешивания ответ от erikkallen из регистров сдвига с линейной обратной связью выглядит правильным. Я только что пробовал, но он дает повторы и дыры.

С уважением, Дэвид Аллан Финч

4
David Allan Finch 11 Фев 2009 в 23:57
Я не думаю, что здесь достаточно информации, чтобы предложить хорошее решение. Сколько целых чисел нужно хешировать? Будут ли дубликаты в этом списке целых чисел? Какой диапазон значений будет у вашего списка?
 – 
EvilTeach
12 Фев 2009 в 04:24
Могут ли упорядоченные целые числа быть отрицательными?
 – 
EvilTeach
12 Фев 2009 в 04:25
Я намеревался использовать весь диапазон беззнаковых длинных или длинных длинных (то есть 32-битных или 64-битных).
 – 
David Allan Finch
12 Фев 2009 в 13:29
Просто любопытно - как тег "генетические алгоритмы" попал на сцену?
 – 
Jason S
12 Фев 2009 в 19:28
Я набрал «Алгоритм», так как мне стало ясно, к чему я стремился. Автозаполнение дело «генетических алгоритмов». Я с радостью сниму метку, если она неправильная.
 – 
David Allan Finch
13 Фев 2009 в 01:12

5 ответов

Лучший ответ

Вопрос теперь в том, нужно ли вам действительно случайное отображение или просто «слабая» перестановка. Предполагая последнее, если вы работаете с 32-битными целыми числами без знака (скажем) в арифметике дополнения до 2, умножение на любое нечетное число является биективным и обратимым отображением. Конечно, то же самое касается XOR, поэтому простой шаблон, который вы можете попробовать использовать, например,

unsigned int hash(int x) {
   return (((x ^ 0xf7f7f7f7) * 0x8364abf7) ^ 0xf00bf00b) * 0xf81bc437;
}

В цифрах нет ничего волшебного. Таким образом, вы можете изменить их, и они могут быть даже рандомизированы. Единственное, множимые должны быть нечетными. И вы должны выполнять вычисления с откатом (без учета переполнения). Это можно перевернуть. Чтобы выполнить инверсию, вы должны быть в состоянии вычислить правильные дополнительные множимые A и B, после чего инверсия будет

unsigned int rhash(int h) {
    return (((x * B) ^ 0xf00bf00b) * A) ^ 0xf7f7f7f7;
}

Вы можете вычислить A и B математически, но для вас проще просто запустить цикл и найти их (то есть в автономном режиме).

Уравнение использует операции XOR, смешанные с умножениями, чтобы сделать отображение нелинейным.

5
Antti Huima 12 Фев 2009 в 07:16
Интересно, что A и B не инвертируют A = 1 / 0x8364abf7 или есть проблемы с округлением.
 – 
David Allan Finch
12 Фев 2009 в 15:47
Нет-нет, в этом смысле они не инверсны. Они обратны в группе конечных умножений по модулю 2 ** 32. Это не имеет ничего общего с обратными в области рациональных чисел.
 – 
Antti Huima
12 Фев 2009 в 18:28
Я быстро набрал первые 100 000 номеров, и результаты выглядят хорошо и очень быстро. Я надеюсь, что завтра у меня будет больше времени, чтобы протестировать его с большим набором чисел.
 – 
David Allan Finch
13 Фев 2009 в 01:15
Да, это хорошо и быстро :) Единственное, что биты младшего порядка довольно линейны ... но это, скорее всего, не повредит вашему приложению. Если вы хотите разбить это, вы можете добавить ((x << 13) | (x >> 19)) к уравнению после первого умножения. Обратное очевидно.
 – 
Antti Huima
13 Фев 2009 в 04:14

Вы можете попробовать создать подходящую сеть Фейстеля. Обычно они используются для криптографии (например, DES), но имеют как минимум 64 бита, поэтому вам может потребоваться создать такой, который соответствует вашим потребностям. По построению они обратимы.

3
starblue 12 Фев 2009 в 00:33
Я думаю, что это правильный ответ, но мне нужно время, чтобы понять, как реализовать сеть Фейстеля.
 – 
David Allan Finch
12 Фев 2009 в 03:27

Предполагая, что ваша цель - распределить сгруппированные значения по всему диапазону,
похоже, что перетасовка битов в каком-то заранее определенном порядке может помочь.
т.е. учитывая 8 бит ABCDEFGH, расположите их как EGDBHCFA или какой-то такой шаблон.

Код будет простой последовательностью масок, сдвигов и добавлений.

1
AShelly 12 Фев 2009 в 00:19
Да, это то, о чем я думал, но я надеялся, что может быть что-то более случайное.
 – 
David Allan Finch
12 Фев 2009 в 00:24

Ммм ... в зависимости от того, много ли у вас чисел, вы можете использовать обычный список stl и упорядочить его по "случайным" критериям

bool
nonsort(int i, int j)
{
    return  random() & 31 >16 ? true : false;
}

std::list<int> li;
// insert elements
li.sort(nonsort);

Затем вы можете получить все целые числа с помощью обычного итератора. Не забудьте инициализировать random с помощью srand () временем или любым другим псевдослучайным значением.

0
Diego Sevilla 12 Фев 2009 в 00:32
Я не знал, что вы можете сделать это с помощью sort, и для небольших значений я думаю, что это было бы хорошим решением. Но я думал о размере беззнакового лонга для всего диапазона.
 – 
David Allan Finch
12 Фев 2009 в 00:35

Для набора ограничений действительно нет решения. Попытка хешировать 32-битное беззнаковое в 32-битное беззнаковое приведет к коллизиям, если вы не сделаете что-то простое, например, сопоставление 1 к 1. Каждое число - это свой хэш.

0
EvilTeach 13 Фев 2009 в 18:40