У меня большой список целых чисел (тысяч), и я хочу извлечь из него первые N (порядка 10-20) уникальных элементов. Каждое целое число в списке встречается примерно три раза.
Написание алгоритма для этого тривиально, но мне интересно, какой самый быстрый и эффективный способ сделать это.
В моем случае есть некоторые дополнительные ограничения и информация:
В моем сценарии использования я несколько раз извлекаю свои уникальные выражения из массива, каждый раз пропуская некоторые элементы с самого начала. Количество элементов, которые я пропускаю, неизвестно во время уникального извлечения. У меня даже нет верхней границы. Поэтому сортировка не эффективна по скорости (я должен сохранить порядок массива).
Целые числа повсюду, поэтому битовый массив в качестве поискового решения неосуществим.
Я хочу избежать временных выделений во время поиска любой ценой.
Мое текущее решение выглядит примерно так:
int num_uniques = 0;
int uniques[16];
int startpos = 0;
while ((num_uniques != N) && (start_pos < array_length))
{
// a temporary used later.
int insert_position;
// Get next element.
int element = array[startpos++];
// check if the element exist. If the element is not found
// return the position where it could be inserted while keeping
// the array sorted.
if (!binary_search (uniques, element, num_uniques, &insert_position))
{
// insert the new unique element while preserving
// the order of the array.
insert_into_array (uniques, element, insert_position);
uniques++;
}
}
Алгоритм двоичного_поиска / вставки в массив выполняет свою работу, но производительность невелика. Вызов insert_into_array много перемещает элементы, и это замедляет все вниз.
Есть идеи?
EDIT
Отличные ответы, ребята! Каждый заслуживает принятого ответа, но я могу дать только один. Я реализую кучу ваших идей и проведу съемки с некоторыми типичными данными. Тот, у кого есть идея, которая приведет к самой быстрой реализации, - это принятый ответ.
Я буду запускать код на современном ПК и встроенном процессоре CortexA8 и как-нибудь взвесить результаты. Также опубликую результаты.
РЕДАКТИРОВАТЬ: Результаты перестрелки
Синхронизация на Core-Duo, 100 итераций по тестовому набору 160 КБ.
Bruteforce (Pete): 203 ticks
Hash and Bruteforce (Antti): 219 ticks
Inplace Binary Tree (Steven): 390 ticks
Binary-Search (Nils): 438 ticks
http://torus.untergrund.net/code/unique_search_shootout.zip (C-источник и тестовые данные)
Дополнительные замечания:
Бинарное дерево на месте абсолютно подходит для истинных случайных распределений (мои тестовые данные имеют тенденцию к возрастанию).
Бинарный поиск очень хорошо работает с моими тестовыми данными для более чем 32 уникальных устройств. Работает почти линейно.