В настоящее время я работаю над проектом встроенного устройства, в котором я столкнулся с проблемами производительности. Профилирование установило операцию O (N), которую я хотел бы исключить.
В основном я имею два массива int A[N]
и short B[N]
. Записи в A
уникальны и упорядочены внешними ограничениями. Наиболее распространенная операция - проверить, появляется ли в A[]
определенное значение A
. Реже, но все же общий - это изменение элемента A[]
. Новое значение не связано с предыдущим значением.
Так как наиболее распространенной операцией является find, то там, где находится B[]
. Это отсортированный массив индексов в A[]
, такой, что A[B[i]] < A[B[j]]
тогда и только тогда, когда i<j
. Это означает, что я могу найти значения в A
, используя двоичный поиск.
Конечно, когда я обновляю A[k]
, мне нужно найти k
в B
и переместить его в новую позицию, чтобы сохранить порядок поиска. Поскольку я знаю старые и новые значения A[k]
, просто a memmove()
подмножества B[]
между старой и новой позицией k
. Это операция O (N), которую мне нужно исправить; так как старые и новые значения A[k]
являются сугубо случайными, я в среднем перемещаюсь о N/2 N/3 элементах.
Я просмотрел std::make_heap
, используя [](int i, int j) { return A[i] < A[j]; }
как предикат. В этом случае я могу легко сделать B[0]
указать наименьший элемент A
, а обновление B
теперь является дешевой операцией по перебалансировке O (log N). Однако, как правило, мне не нужно наименьшее значение A, мне нужно найти, присутствует ли какое-либо данное значение. И это теперь поиск O (N log N) в B
. (Половина моих элементов N находится в журнале глубины кучи N, четверть в (log N) -1 и т.д.), Что не улучшает поиск немого O (N) непосредственно в A
.
Учитывая, что std::set
имеет O (log N) insert и find, я бы сказал, что здесь можно получить такую же производительность для обновления и поиска. Но как мне это сделать? Мне нужен другой заказ для B
? Другой тип?
B
в настоящее время является short [N]
, потому что A
и B
вместе имеют размер моего кеша процессора, а моя основная память намного медленнее. Переход от 6 * N до 8 * N байтов не будет приятным, но все же приемлемым, если моя находка и обновление перейдут в O (log N).