В настоящее время я работаю над проектом встроенного устройства, в котором я столкнулся с проблемами производительности. Профилирование установило операцию 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).