Как найти медиану чисел за линейное время, используя кучи?

Википедия говорит:

Алгоритмы выбора. Поиск минимального, максимального, минимального и максимального значений, медианы или даже k-го по величине элемента можно выполнить за линейное время с использованием кучи.

Все это говорит о том, что это можно сделать, а не о том, как это сделать.

Можете ли вы дать мне некоторое представление о том, как это можно сделать с помощью кучи?


person Lazer    schedule 05.04.2010    source источник
comment
Я думаю, что это может быть неправильно насчет медианы и k-го по величине, но я был бы очень рад, если бы это оказалось неверным, особенно для медианы.   -  person Paul R    schedule 05.04.2010
comment
Дубликат: заголовок stackoverflow.com/questions/810657/   -  person Jacob    schedule 05.04.2010
comment
Не дубликат. (Я думаю, но могу ошибаться) речь идет не об алгоритмах выбора, а о том, чтобы медиана составляла время O (1) после создания кучи.   -  person    schedule 05.04.2010
comment
@Paul R: если куча отсортирована, разве вам не нужно просто пройти по дереву в обратном порядке для k элементов, чтобы получить k-й по величине?   -  person ANeves thinks SE is evil    schedule 05.04.2010
comment
@Jacob: это не дубликат этого вопроса. В другом вопросе у него было очень конкретное количество элементов, из которых он получает медиану. В этом вопросе нет заданного количества элементов, и набор может быть произвольного размера. Алгоритм в другом вопросе может быть таким же ответом, но вопрос не тот же.   -  person mmr    schedule 05.04.2010
comment
@sr pt: Я думаю, если у вас есть какая-либо отсортированная структура данных, вы можете найти медиану в O (1), но, по-видимому, они подразумевают в приведенном выше утверждении, что вы можете создать кучу и найти медиану за линейное время? Если это просто линейное время для нахождения медианы после создания кучи, то это не очень примечательно.   -  person Paul R    schedule 05.04.2010


Ответы (7)


Вы бы использовали кучу min-max-median, чтобы найти минимум, максимум и медиану за постоянное время (и взять линейное время для построения кучи). Вы можете использовать деревья статистики порядка, чтобы найти k-е наименьшее/наибольшее значение. Обе эти структуры данных описаны в этой статье по мин- макс. кучи [PDF]. Минимальные кучи — это двоичные кучи, которые чередуются между минимальными и максимальными кучами.

Из бумаги:

Мин-макс-медианная куча — это бинарное дерево со следующими свойствами:

  1. Медиана всех элементов находится в корне

  2. Левое поддерево корня представляет собой минимальную кучу Hl размера потолка[((n-1)/2)], содержащую элементы, меньшие или равные медиане. Правое поддерево представляет собой максимально-минимальную кучу Hr размера floor[((n-1)/2)], содержащую только элементы, большие или равные медиане.

Далее в статье объясняется, как построить такую ​​кучу.

При более внимательном прочтении статьи выясняется, что для построения кучи min-max-median необходимо сначала найти медиану (FTA: найти медиану всех n элементов, используя любой из известных линейных методов). временные алгоритмы). Тем не менее, как только вы построили кучу, вы можете поддерживать медиану, просто поддерживая баланс между кучей min-max слева и кучей max-min справа. DeleteMedian заменяет корень либо минимумом кучи max-min, либо максимумом кучи min-max (в зависимости от того, что поддерживает баланс).

Поэтому, если вы планируете использовать кучу min-max-median для нахождения медианы фиксированного набора данных, вы SOL, но если вы используете его для меняющегося набора данных, это возможно.

person Niki Yoshiuchi    schedule 09.04.2010
comment
На самом деле обе кучи могут быть как min-max, так и max-min, и алгоритм все равно будет работать с той же общей сложностью. - person dhruvbird; 23.04.2011
comment
На самом деле достаточно и проще всего min(max) куча для дерева с элементами не меньше (больше) медианы. - person greybeard; 29.04.2021
comment
How do I [exploit heaps to find the median in linear time]? По сути, этот ответ и статья, на которой он основан, не дают подсказки. (Я думаю, что нужно лаять в кучу не то дерево.) - person greybeard; 29.04.2021
comment
(Что здесь написано FTA?) - person greybeard; 29.04.2021

См. эту страницу в Википедии, посвященную алгоритмам выбора. В частности, посмотрите на алгоритм BFPRT и алгоритм Median of Medians. BFPRT является вероятностно-линейным и основан на быстрой сортировке; Медиана медиан гарантированно является линейной, но имеет большой постоянный коэффициент, поэтому на практике может потребоваться больше времени, в зависимости от размера вашего набора данных.

Если у вас есть всего несколько сотен или тысяч элементов, из которых нужно выбрать медиану, я подозреваю, что проще всего выполнить простую быструю сортировку с последующим прямым индексированием.

person Dale Hagglund    schedule 05.04.2010
comment
@Dale Hagglund: используя кучи? - person Lazer; 05.04.2010
comment
linear несовместим с использованием кучи, если вы не добавляете стоимость предварительной обработки бесплатно. Тем не менее, я должен был сделать это ясно в начале моего поста. - person Dale Hagglund; 05.04.2010
comment
Неужели так сложно применить концепцию кучи к разделам и опорным точкам? - person tloflin; 05.04.2010
comment
@tlofin: извини, но я не уверен, о чем ты спрашиваешь. - person Dale Hagglund; 05.04.2010
comment
Извините, я отвечал на eSKay. Думаю, мне нужно начать использовать эти @s. - person tloflin; 06.04.2010

Вероятно, есть лучшие алгоритмы, но вот как я это сделаю:

Имейте два ведра и значение. Значение является медианным, два сегмента «больше медианы» и «меньше медианы». Для каждого элемента x в массиве перебалансируйте сегменты так, чтобы big_bucket и small_bucket отличались по размеру не более чем на 1. При перемещении элементов из большого ведра в маленькое они сначала должны пройти через медианное значение, чтобы попасть туда (то есть разница в 2 успешно переместит элемент из одного ведра в другое, а разница в 1 переместит элемент от одного сегмента до медианного значения.) В конце вашего первого прохода по массиву значение должно быть вашим медианным значением.

person fbrereto    schedule 05.04.2010
comment
@fbrereto: Какова временная сложность вашего алгоритма? Я думаю, что этот алгоритм НЕ является линейным. - person Lazer; 05.04.2010
comment
Это был бы один проход по исходному массиву, а операции с ведрами были бы push/pop, которые могут выполняться за постоянное время (поскольку известно, что их размер не превышает N/2+1), поэтому сверху моей головы я подозреваю, что это можно сделать за O (N). Пожалуйста, поправьте меня, если я что-то пропустил. - person fbrereto; 06.04.2010
comment
Хм... нужно было бы отсортировать ведра, что не является операцией O (N) (модификация сортировки по основанию). - person fbrereto; 06.04.2010
comment
@fbrereto: хранить minbucket и maxbucket в виде кучи. Это в основном та же концепция, что и другие решения. Не уверен, что явный средний элемент имеет большое значение. - person smci; 26.08.2012

Возможно, его не было, когда был задан первоначальный вопрос, но теперь в вики есть ссылка на источник, и вот она: http://ftp.cs.purdue.edu/research/technical_reports/1991/TR%2091-027.pdf

В частности, перейдите на страницу 17 и посмотрите описание RSEL4. В теореме 3.2 они доказывают, что временная сложность этого k-го алгоритма выбора равна O(k). Таким образом, вам потребуется O (n), чтобы построить кучу, и дополнительно O (k), чтобы найти k-й наименьший элемент.

Это не так просто, как предполагалось в некоторых других ответах.

person Shlomi    schedule 15.02.2012
comment
Профессор Фредриксон вышел на пенсию в 2017 г. (по состоянию на начало 21 г. продолжает публиковаться); его каталоги ftp Purdue пусты. Хорошо это или плохо, но скан CSD-TR-91-027 доступен на free.fr, RSEL 4 очень похоже на RSELA. Для мучительно подробного анализа см. Kenn Daniel, Casper Færgemand : Выделение в куче - person greybeard; 29.04.2021

если вы знаете больше о структуре данных кучи, вы легко поймете, что это действительно так. Структура кучи может быть построена за время O (n), есть минимальная куча и максимальная куча. min корневой элемент кучи даст вам наименьший элемент. максимальный корневой элемент кучи даст вам максимальный элемент. Просто построив кучу, вы найдете мин и макс. та же идея для медианы и k-го наибольшего, при создании кучи вы можете найти медиану и k-й наибольший, посмотрев на левую или правую ветвь дерева и сохранив постоянный объем памяти для хранения номера элемента. и Т. Д.

person DarthVader    schedule 08.04.2010
comment
@ user177883: как вы будете строить кучу, чтобы корень был медианой? - person Lazer; 09.04.2010

Сохраните первое целое число в массиве и установите счетчик равным 1. Затем выполните цикл по оставшимся целым числам в векторе. Если текущее целое число в массиве совпадает с сохраненным, счетчик увеличивается на единицу, в противном случае счетчик уменьшается на единицу. Если счетчик когда-либо достигнет нуля, выбросьте сохраненное целое число и замените его текущим целым числом в массиве. Когда вы, наконец, перебрали все целые числа, у вас остался один кандидат. Затем вам нужно снова пройтись по массиву и подсчитать появление кандидата, чтобы убедиться, что это действительно доминатор.

static int FindDominator(int[] arr)
{
int counter = 1;
int candidate = arr[0];
for(int i = 1; i < n; i++)
{
   if(arr[i] == candidate) counter++
    else 
   {
        counter--;
        if(counter == 0) { candidate = arr[i]; counter = 1; }
    }
}
counter = 0;
for(int i = 0;  i < n; i++)
{
    if(arr[i] == candidate) counter++;
}
if(counter > n / 2) return candidate;
else return -1;
}
person jaycee    schedule 26.03.2015

Очевидно, что min и max в O(n) просты и не требуют кучи.

K-й самый большой можно сделать достаточно просто, поддерживая кучу k-размера верхних значений k на данный момент. Время выполнения будет O (n * logk). Вы могли бы назвать это линейным временем, если k имеет фиксированный размер и k ‹‹ n.

Я не думаю, что медиана возможна. Простое создание кучи размером O(n) требует времени O(n*logn).

Редактировать: Хорошо, если подумать, IVlad оказался прав. Вы можете создать кучу за O(n) фиксированного размера. Но ... это не помогает ОП с его медианным вопросом. Техника создания линейной кучи создает только допустимую кучу в качестве конечного результата. Простой подход к выполнению n вставок, приводящий к правильной куче после каждого шага, равен O(n*logn).

Мне кажется, что использование кучи для поиска медианы потребует использования этих работающих подкуч. Например, здесь был опубликован ответ (который, кажется, теперь удален), который ссылался на сообщение в блоге, предлагающее алгоритм для этой проблемы. Он отслеживал текущую медиану, используя две кучи (меньшую половину и большую половину), поскольку он выполняет один проход по данным. Это потребует более медленного, наивного подхода к куче, потому что он зависит от поддержания допустимых куч при вставке и удалении из них.

Есть ли другой способ найти медиану, используя линейную технику создания однократной кучи?

person Alan    schedule 05.04.2010
comment
Просто создание кучи размером O (n) требует времени O (n * logn) - неправильно, вы можете создать кучу за время O (N). - person IVlad; 05.04.2010
comment
@IVlad - Вы можете создать кучу для уже отсортированных данных за время O (n), и вы можете создать кучу фиксированного размера за время O (n), но я не вижу ни одного из этих предварительных условий в вопросе. - person Jeffrey L Whitledge; 05.04.2010
comment
Если данные уже отсортированы, вам не нужна куча, чтобы найти медиану или любую другую цель в OP. - person Alan; 05.04.2010
comment
@Jeffrey L Whitledge - вы также можете создать кучу для несортированных данных за время O (n). Отсортированный набор данных уже является кучей, поэтому создание кучи из нее на самом деле составляет O (1). Я почти уверен, что вопрос относится к вводу фиксированного размера, алгоритм выбора подразумевает это. - person IVlad; 05.04.2010
comment
Если вопрос относится к вводу фиксированного размера, то выражение линейное время не имеет смысла. Под кучей фиксированного размера я имел в виду ту, которая может быть использована для поиска, скажем, 10-го по величине элемента несортированного множества. Алгоритм поиска m-го наибольшего или наименьшего значения будет O(n), где n — размер входных данных, а m — фиксированное число, связанное с алгоритмом. Если m разрешено изменять как часть ввода, то манипуляции с кучей больше не являются постоянным временем, а становятся O (n log m). - person Jeffrey L Whitledge; 05.04.2010