Мне нужен очень быстрый алгоритм для следующей задачи. Я уже реализовал несколько алгоритмов, которые его завершают, но все они слишком медленные для нужной мне производительности. Он должен быть достаточно быстрым, чтобы алгоритм мог запускаться не менее 100 000 раз в секунду на современном процессоре. Он будет реализован на C++.
Я работаю с промежутками/диапазонами, структурой, которая имеет начальную и конечную координаты на линии.
У меня есть два вектора (динамические массивы) диапазонов, и мне нужно их объединить. Один вектор — это src, а другой — dst. Векторы сортируются по начальным координатам отрезка, а отрезки не перекрываются в пределах одного вектора.
Промежутки в векторе src должны быть объединены с промежутками в векторе dst, чтобы результирующий вектор все еще был отсортирован и не имел перекрытий. Т.е. если во время слияния обнаруживаются перекрытия, два пролета объединяются в один. (Объединение двух пролетов — это всего лишь вопрос изменения координат в структуре.)
Теперь есть еще одна загвоздка: промежутки в векторе src должны быть «расширены» во время слияния. Это означает, что константа будет добавлена к началу и другая (более крупная) константа к конечной координате каждого интервала в src. Это означает, что после расширения диапазонов src они могут перекрываться.
На данный момент я пришел к выводу, что это невозможно сделать полностью на месте, необходимо какое-то временное хранилище. Я думаю, что это должно быть выполнимо за линейное время по количеству суммированных элементов src и dst.
Любое временное хранилище, вероятно, может быть разделено между несколькими запусками алгоритма.
Два основных подхода, которые я пробовал, являются слишком медленными:
Добавьте все элементы src к dst, расширяя каждый элемент перед его добавлением. Затем запустите сортировку на месте. Наконец, выполните итерацию по результирующему вектору, используя указатель «чтение» и «запись», при этом указатель чтения опережает указатель записи, объединяя диапазоны по мере их прохождения. Когда все элементы объединены (указатель чтения достигает конца), dst усекается.
Создайте временный рабочий вектор. Выполните наивное слияние, как описано выше, многократно выбирая следующий элемент либо из src, либо из dst и объединяя его с рабочим вектором. Когда закончите, скопируйте рабочий вектор в dst, заменив его.
Проблема первого метода заключается в том, что сортировка выполняется за O((m+n)*log(m+n)) вместо O(m+n) и имеет некоторые накладные расходы. Это также означает, что вектор dst должен вырасти намного больше, чем ему действительно нужно.
Второй имеет основную проблему большого количества копий и снова выделения/освобождения памяти.
Структуры данных, используемые для хранения/управления диапазонами/векторами, могут быть изменены, если вы считаете, что это необходимо.
Обновление: забыл сказать, насколько велики наборы данных. Наиболее распространенными случаями являются от 4 до 30 элементов в любом векторе, и либо dst пуст, либо существует большое количество перекрытий между интервалами в src и dst.