Мне нужно рассчитать бегущую медиану:
Ввод: , , вектор .k ( x 1 , x 2 , … , x n )
Вывод: vector , где - это медиана .y i ( x i , x i + 1 , … , x i + k - 1 )
(Нет мошенничества с приближениями; я хотел бы иметь точные решения. Элементы являются большими целыми числами.)
Существует тривиальный алгоритм, который поддерживает дерево поиска размера ; общее время работы . (Здесь «дерево поиска» относится к некоторой эффективной структуре данных, которая поддерживает вставки, удаления и срединные запросы в логарифмическом времени.)O ( n log k )
Тем не менее, это кажется немного глупым для меня. Мы эффективно изучим всю статистику заказов во всех окнах размера , а не только в медианах. Более того, на практике это не слишком привлекательно, особенно если велико (большие деревья поиска имеют тенденцию быть медленными, накладные расходы на потребление памяти нетривиальны, эффективность кеширования часто низкая и т. Д.).к
Можем ли мы сделать что-нибудь существенно лучше?
Существуют ли нижние оценки (например, является ли тривиальный алгоритм асимптотически оптимальным для модели сравнения)?
Изменить: Дэвид Эппштейн дал хороший нижний предел для модели сравнения! Интересно, возможно ли все же сделать что-то немного более умное, чем тривиальный алгоритм?
Например, можем ли мы сделать что-то в этом духе: разделить входной вектор на части размера ; сортировать каждую часть (отслеживая исходные позиции каждого элемента); а затем использовать кусочно отсортированный вектор, чтобы эффективно найти текущие медианы без каких-либо вспомогательных структур данных? Конечно, это все равно будет , но на практике сортировка массивов, как правило, происходит намного быстрее, чем поддержка деревьев поиска.O ( n log k )
Изменить 2: Saeed хотел увидеть некоторые причины, почему я думаю, сортировка быстрее, чем операции дерева поиска. Вот очень быстрые тесты для , : n = 10 8
- ≈ 8 с: сортировка векторов с элементами каждыйк
- ≈ 10 с: сортировка вектора с элементами
- ≈ 80 с: вставок и удалений в хеш-таблице размерак
- ≈ 390 с: вставок и удалений в сбалансированном дереве поиска размерак
Хеш-таблица существует только для сравнения; это не имеет прямого использования в этом приложении.
Таким образом, мы имеем почти 50-кратное различие в производительности сортировки и сбалансированных операциях дерева поиска. И все станет намного хуже, если мы увеличим .
(Технические детали: Данные = случайные 32-разрядные целые числа. Компьютер = типичный современный ноутбук. Тестовый код был написан на C ++ с использованием стандартных библиотечных процедур (std :: sort) и структур данных (std :: multiset, std :: unsorted_multiset). Я использовал два разных компилятора C ++ (GCC и Clang) и две разные реализации стандартной библиотеки (libstdc ++ и libc ++). Традиционно std :: multiset был реализован как высокооптимизированное красно-черное дерево.)
источник
Ответы:
Вот нижняя граница от сортировки. Учитывая, что входной набор длины n должен быть отсортирован, создайте вход для вашей текущей задачи медианы, состоящей из n - 1 копий числа, меньшего, чем минимум S , затем самого S , затем n - 1 копий числа, большего, чем максимум S , и установите k = 2 n - 1 . Ходовые медианы этого входа такие же , как в отсортированном порядке S .S N n - 1 S S n - 1 S k = 2 n - 1 S
Таким образом, в сравнительной модели вычислений требуется время . Возможно, если ваши входные данные являются целыми числами и вы используете алгоритмы целочисленной сортировки, вы можете добиться большего.Ω ( n logн )
источник
Изменить: Этот алгоритм теперь представлен здесь: http://arxiv.org/abs/1406.1717
Да, для решения этой проблемы достаточно выполнить следующие операции:
Очень грубо, идея заключается в следующем:
Для каждого :i
Связанные списки - это просто массивы -элементных индексов, поэтому они легковесны (за исключением того, что локальность доступа к памяти плохая).k
Вот пример реализации и тесты:
Вот график времени работы (для ):n≈2⋅106
источник
источник