В чем смысл make_heap?

Может кто-нибудь, пожалуйста, скажите мне, в чем смысл шаблонов функций кучи STL, таких как std::make_heap? Зачем кому-то их использовать? Есть ли практическое применение?


person rlbond    schedule 03.06.2009    source источник
comment
Я хотел бы увидеть, как вы выполняете сортировку кучей без функции make_heap :P   -  person workmad3    schedule 04.06.2009
comment
@workmad3 Нет проблем. gist.github.com/luizfls/fe492e9f625f25d081e433fd53f01d31   -  person luizfls    schedule 26.04.2021
comment
Вау, это был взрыв из прошлого :) 12 лет назад я был здесь намного активнее.   -  person workmad3    schedule 20.05.2021


Ответы (7)


Если вы хотите создать приоритетную очередь из списка, вы можете использовать сделать_кучу:

Внутри куча представляет собой дерево, в котором каждый узел ссылается на значения, не превышающие его собственное значение. В кучах, созданных make_heap, конкретная позиция элемента в дереве определяется не ссылками, потребляющими память, а его абсолютным положением в последовательности, где *first всегда является самым высоким значением в куче.

Кучи позволяют добавлять или удалять элементы из нее за логарифмическое время с помощью функций push_heap и pop_heap, сохраняющих свойства кучи.

person akappa    schedule 03.06.2009
comment
Изменяется ли структура vector, если к нему применяется make_heap, поскольку он должен поддерживать быстрый поиск? Чем это отличается от сортировки вектора? - person Sumit Gera; 24.10.2013
comment
Куча — это просто последовательная перестановка элементов, которая позволяет соблюдать ограничения, описанные выше. То есть make_heap просто шифрует ваши данные в вашем векторе, вот и все. Сортировка элемента также может быть вариантом, но для вставки и удаления требуется линейное время, а не логарифмическое (вам нужно освободить место для нового элемента при добавлении, а для этого, например, требуется линейное время) . - person akappa; 08.11.2013

На ваш прямой вопрос хорошо ответил бы класс алгоритмов и структур данных. Кучи используются повсеместно в алгоритмах информатики. Цитируя приведенную ниже функцию make_heap, «куча — это дерево, в котором каждый узел ссылается на значения, не превышающие его собственное значение». Несмотря на то, что для кучи существует множество приложений, я использую наиболее часто проблемы поиска, когда вы хотите эффективно отслеживать отсортированный список из N значений.

У меня было такое же замешательство, как и у вас, когда я впервые столкнулся с функциями кучи STL. Хотя мой вопрос был немного о другом. Я задался вопросом: «Почему куча STL не относится к тому же классу структур данных, что и std::vector?» Я думал, что это должно работать так:

std::heap< int > my_heap;
my_heap.heap_insert( 7 );
my_heap.heap_insert( 3 );

Идея функций кучи STL заключается в том, что они позволяют создавать структуру данных кучи из нескольких различных базовых контейнеров STL, включая std::vector. Это может быть очень полезно, если вы хотите передать контейнер для использования в других местах ваших программ. Это также немного приятно, потому что вы можете выбрать базовый контейнер вашей кучи, если вы решите использовать что-то отличное от std::vector. Все, что вам действительно нужно, это следующее:

template <class RandomAccessIterator>
  void make_heap ( RandomAccessIterator first, RandomAccessIterator last );

Это означает, что вы можете создавать множество различных контейнеров в куче. Компаратор также является необязательным в сигнатуре метода, вы можете узнать больше о различных вещах, которые вы можете попробовать, на страницах STL для функции make_heap.

Ссылки:

person James Thompson    schedule 03.06.2009
comment
На самом деле существует класс шаблона кучи, std::priority_queue, поэтому вам не нужно использовать std::make_heap для создания кучи. - person Fred Foo; 28.08.2013

Вы должны использовать std::make_heap() вместе с std::push_heap() и std::pop_heap() для поддержки двоичной кучи поверх вектора или массива; последние две функции поддерживают инвариант кучи. Вы также можете использовать std::heap_sort() для сортировки такой кучи. Хотя верно то, что вы можете использовать std::priority_queue для приоритетной очереди, это не позволит вам добраться до ее внутренностей, что, возможно, вы захотите сделать. Кроме того, std::make_heap() и std::heap_sort() вместе составляют очень простой способ выполнения пирамидальной сортировки в C++.

person newacct    schedule 04.06.2009
comment
Это единственный ответ, в котором на самом деле правильно упоминается, что эти функции создают и обслуживают бинарную кучу (именно поэтому она работает с итераторами, а не с древовидной структурой). - person MicroVirus; 16.08.2018

std::make_heap почти никогда не следует использовать на практике. Хотя кучи полезны для очередей с приоритетом, это не объясняет, почему вы хотите вручную поддерживать структуру. std::priority_queue имеет гораздо более полезный интерфейс, если все, что вам нужно, это приоритетная очередь.

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

Я только один раз использовал операции с кучей напрямую, потому что мне нужно было какое-то время использовать вектор в качестве приоритетной очереди, а затем отсортировать его. Скорее всего, вам никогда не понадобится std::make_heap.

Если вам нужна приоритетная очередь с возможностью смены элементов, вы можете использовать std::set. Вы можете получить наименьший или наибольший элемент с помощью *s.begin() или *s.rbegin() соответственно и обновить элемент, удалив старое значение и вставив новое.

person Jørgen Fogh    schedule 09.04.2011
comment
Как отмечали другие два года назад, когда был задан этот вопрос, у функций есть преимущества. В частности, вы можете быстро перейти от несортированных данных к отсортированным данным по мере необходимости, не поддерживая два отдельных набора данных. std::priority_queue полезно, если все, что вам когда-либо нужно, это куча, но если ваши потребности более сложны, выполнение черновой работы самостоятельно [которую функции кучи делают довольно простой] может быть весьма полезным. - person Dennis Zickefoose; 09.04.2011
comment
@Dennis Zickefoose: Насколько я могу судить, я единственный, кто на самом деле упомянул случай, когда вы сортируете данные после их использования в качестве приоритетной очереди. Вот почему я написал почти никогда. Просто сказать, что make_heap используется для создания кучи, не является полезным ответом, тем более что вы редко хотите использовать его, если вам только нужна куча. - person Jørgen Fogh; 21.03.2013
comment
@JørgenFogh У std::priority_queue нет способа преобразовать известный набор в очередь. Создание очереди - это O (n), если делается все сразу, но O (n log n), если делается по одному элементу за раз. Если это имеет значение, вы не можете использовать std::priority_queue - person Kyle Butt; 24.01.2017
comment
@KyleButt Правильно. Моя точка зрения заключается в том, что это вряд ли имеет значение. Простота использования, вероятно, имеет гораздо большее значение, особенно потому, что люди склонны использовать функции неправильно. - person Jørgen Fogh; 25.01.2017
comment
std::make_heap полезен, когда вы добавляете много вещей одновременно в кучу и хотите переделать ее только один раз. - person Dev Null; 20.09.2018

По сути, есть два способа построить [бинарную] кучу: создать пустую кучу и вставить в нее каждый элемент по одному или взять диапазон значений и объединить их в кучу.

Каждая операция push в куче занимает O (logn) времени, поэтому, если вы помещаете N элементов в кучу, это займет O (NlogN) времени. Однако для создания двоичной кучи из массива значений требуется всего O (N) времени.

Таким образом, имеет больше смысла вставлять каждый элемент в массив (или другой контейнер, который поддерживает итераторы произвольного доступа), а затем вызывать make_heap() для массива, чем для сохранения структуры кучи при вставке.

person Niki Yoshiuchi    schedule 04.06.2009

В дополнение к вышесказанному алгоритм сортировки STL представляет собой introsort, представляющий собой смесь быстрой сортировки и heapsort (он переключается с быстрой сортировки на heapsort, если первая работает плохо). make_heap создает структуру кучи, необходимую для запуска пирамидальной сортировки, необходимой для начальной сортировки.

person Todd Gardner    schedule 03.06.2009

Они используются для построения и поддержки структуры данных кучи.

person Community    schedule 03.06.2009