У меня есть список N 64-битных целых чисел, чьи биты представляют собой малые множества. Каждое целое число имеет не более k бит, заданное равным 1. Учитывая битовую маску, я хотел бы найти первый элемент в списке, который соответствует маске, т.е. element & mask == element
.
Пример:
Если мой список:
index abcdef
0 001100
1 001010
2 001000
3 000100
4 000010
5 000001
6 010000
7 100000
8 000000
а моя маска 111000
, первый элемент, соответствующий маске, имеет индекс 2.
Метод 1:
Линейный поиск по всему списку. Это занимает время O (N) и O (1).
Метод 2:
Предкоммутировать дерево всех возможных масок, и в каждом node сохранить ответ для этой маски. Это занимает O (1) время для запроса, но занимает O (2 ^ 64).
Вопрос:
Как я могу найти первый элемент, соответствующий маске быстрее, чем O (N), но при этом использовать разумное пространство? Я могу позволить себе потратить полиномиальное время на предвычисление, потому что будет много запросов. Ключ в том, что k мал. В моем приложении k <= 5 и N находится в тысячах. Маска имеет много 1s; вы можете предположить, что он нарисован равномерно из пространства 64-битных целых чисел.
Update:
Вот пример набора данных и простая тестовая программа, которая работает в Linux: http://up.thirld.com/binmask.tar.gz. Для large.in
, N= 3779 и k= 3. Первая строка N, за которой следуют N неподписанные 64-битные int, представляющие элементы. Скомпилируйте с помощью make
. Запустите с помощью ./benchmark.e >large.out
, чтобы создать истинный вывод, который вы можете затем разбить. (Маски генерируются случайным образом, но случайное семя фиксировано.) Затем замените функцию find_first()
на вашу реализацию.
Простой линейный поиск намного быстрее, чем я ожидал. Это потому, что k мал, и поэтому для случайной маски совпадение встречается очень быстро в среднем.