Heapsort Time Сложность

Heapsort Time Sloznost



Heap Sort, записанный как Heapsort, представляет собой разновидность алгоритма сортировки. Он берет частично упорядоченный список и создает из него отсортированный список. Сортировка может быть по возрастанию или по убыванию. В этой статье сортировка по возрастанию. Обратите внимание, что пирамидальная сортировка не сортирует не полностью неотсортированный список. Он сортирует частично упорядоченный (отсортированный) список. Этот частично упорядоченный список представляет собой кучу. В этой статье куча рассматривается как минимальная (возрастающая) куча.

Куча называется «частично упорядоченной», а не «частично отсортированной». Слово «сортировка» означает полное упорядочение (полная сортировка). Куча не является частично упорядоченной произвольно. Куча частично упорядочена по критерию (шаблону), как показано ниже.

Итак, пирамидальная сортировка состоит из двух этапов: построения кучи и извлечения упорядоченного элемента из вершины кучи. На втором этапе после каждого извлечения куча перестраивается. Каждая перестройка выполняется быстрее, чем исходный процесс сборки, поскольку перестройка выполняется из предыдущей сборки, в которой был удален один элемент. И при этом heapsort сортирует полностью несортированный список.







Цель этой статьи — кратко объяснить пирамидальную сортировку, а затем определить ее временную сложность (см. значение временной сложности ниже). Ближе к концу кодирование выполняется на C++.



Минимальная куча

Куча может быть минимальной кучей или максимальной кучей. Максимальная куча — это та, в которой первый элемент является самым высоким элементом, а все дерево или соответствующий список частично упорядочены в порядке убывания. Минимальная куча — это та, в которой первый элемент является наименьшим элементом, а весь список частично упорядочен в порядке возрастания. В этой статье рассматривается только минимальная куча. Примечание: в теме кучи элемент также называется узлом.



Куча — это полное бинарное дерево. Бинарное дерево можно представить в виде массива (списка); читать сверху вниз и слева направо. Свойство кучи для минимальной кучи заключается в том, что родительский узел меньше или равен каждому из двух своих дочерних узлов. Пример неупорядоченного списка:





9 19 24 5 3 одиннадцать 14 22 7 6 17 пятнадцать нулевой нулевой нулевой
0 1 два 3 4 5 6 7 8 9 10 одиннадцать 12 13 14

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

Связь между узлами и индексами

Помните, что куча — это полное бинарное дерево до конфигурации кучи (свойство кучи). Предыдущий список еще не является кучей, потому что элементы не подчиняются свойству кучи. Он становится кучей после перестановки элементов в частичном порядке в соответствии со свойством min-heap. Частичный порядок можно рассматривать как частичную сортировку (хотя слово «сортировка» означает полный порядок).



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

два * я + 1

и правый ребенок находится в индексе:

два * я + два

Это для индексации с отсчетом от нуля. Таким образом, у родителя с индексом 0 есть левый дочерний элемент с индексом 2×0+1=1 и правый дочерний элемент с индексом 2×0+2=2. У родителя с индексом 1 есть левый дочерний элемент с индексом 2×1+1=3 и правый дочерний элемент с индексом 2×1+2=4; и так далее.

По свойству min-heap родитель в i меньше или равен левому дочернему элементу в 2i+1 и меньше или равен правому дочернему элементу в 2i+2.

куча

Heapification означает построение кучи. Это означает переставить элементы списка (или соответствующего дерева) так, чтобы они удовлетворяли свойству кучи. В конце процесса кучи список или дерево представляет собой кучу.

Если предыдущий несортированный список увеличить, он станет:

3 5 одиннадцать 7 6 пятнадцать 14 22 9 19 17 24 нулевой нулевой нулевой
0 1 два 3 4 5 6 7 8 9 10 одиннадцать 12 13 14

Примечание: в списке 12 элементов, а не 15. Во второй строке находятся индексы. В процессе построения кучи элементы приходилось проверять, а некоторые менять местами.

Обратите внимание, что наименьший и первый элемент равен 3. Остальные элементы следуют восходящим, но волнообразным образом. Если левый и правый дочерние элементы в позициях 2i+1 и 2i+2 больше или равны родительскому элементу в i, то это минимальная куча. Это не полный порядок или сортировка. Это частичное упорядочение в соответствии со свойством кучи. Отсюда начинается следующий этап сортировки кучи.

Увеличьте временную сложность

Временная сложность — это относительное время выполнения некоторого кода. Его можно рассматривать как количество основных операций для завершения этого кода. Существуют разные алгоритмы построения кучи. Наиболее эффективные и быстрые непрерывно делят список на два, проверяя элементы снизу, а затем выполняя некоторую замену элементов. Пусть N будет количеством практических элементов в списке. В этом алгоритме максимальное количество основных операций (подкачки) равно N. Временная сложность для нагромождения задается ранее как:

О ( н )

Где n равно N и максимально возможное количество основных операций. Эта запись называется записью Big-O. Он начинается с O в верхнем регистре, за которым следуют круглые скобки. В скобках указано максимально возможное количество операций.

Помните: сложение может стать умножением, если одно и то же прибавляемое повторяется.

Хипсорт Иллюстрация

Предыдущий несортированный список будет использоваться для иллюстрации пирамидальной сортировки. Данный список таков:

9 19 24 5 3 одиннадцать 14 22 7 6 17 пятнадцать

Минимальная куча, созданная из списка:

3 5 одиннадцать 7 6 пятнадцать 14 22 9 19 17 24

Первым этапом heapsort является создание кучи, которая была произведена. Это частично упорядоченный список. Это не отсортированный (полностью отсортированный) список.

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

В конце концов, в новом массиве все элементы будут отсортированы (полностью) в порядке возрастания; и уже не просто частично заказано.

На втором этапе первое, что нужно сделать, это удалить 3 и поместить его в новый массив. Результаты:

3

а также

5 одиннадцать 7 6 пятнадцать 14 22 9 19 17 24

Остальные элементы должны быть загружены до того, как будет извлечен первый элемент. Куча остальных элементов может стать:

5 6 7 9 пятнадцать 14 22 одиннадцать 19 17 24

Извлечение 5 и добавление в новый список (массив) дает результаты:

3 5

а также

6 7 9 пятнадцать 14 22 одиннадцать 19 17 24

Наполнение оставшегося набора даст:

6 7 9 пятнадцать 14 22 одиннадцать 19 17 24

Извлечение 6 и добавление в новый список (массив) дает результаты:

3 5 6

а также

7 9 пятнадцать 14 22 одиннадцать 19 17 24

Наполнение оставшегося набора даст:

7 9 одиннадцать 14 22 пятнадцать 19 17 24

Извлечение 7 и добавление его в новый список дает результаты:

3 5 6 7

а также

9 одиннадцать 14 22 пятнадцать 19 17 24

Наполнение оставшегося набора дает:

9 одиннадцать 14 22 пятнадцать 19 17 24

Извлечение 9 и добавление в новый список дает результаты:

3 5 6 7 9

а также

одиннадцать 14 22 пятнадцать 19 17 24

Наполнение оставшегося набора дает:

одиннадцать 14 17 пятнадцать 19 22 24

Извлечение 11 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать

а также

14 17 пятнадцать 19 22 24

Наполнение оставшегося набора даст:

14 17 пятнадцать 19 22 24

Извлечение 14 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать 14

а также

17 пятнадцать 19 22 24

Наполнение оставшегося набора даст:

пятнадцать 17 19 22 24

Извлечение 15 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать 14 пятнадцать

а также

17 19 22 24

Наполнение оставшегося набора даст:

17 19 22 24

Извлечение 17 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать 14 пятнадцать 17

а также

19 22 24

Наполнение оставшегося набора даст:

19 22 24

Извлечение 19 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать 14 пятнадцать 17 19

а также

22 24

Наполнение оставшегося набора дает:

22 24

Извлечение 22 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать 14 пятнадцать 17 19 22

а также

24

Наполнение оставшегося набора дает:

24

Извлечение 24 и добавление его в новый список дает результаты:

3 5 6 7 9 одиннадцать 14 пятнадцать 17 19 22 24

а также

- - -

Массив кучи теперь пуст. Все элементы, которые у него были в начале, теперь находятся в новом массиве (списке) и отсортированы.

Алгоритм Heapsort

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

  • Увеличить несортированный список.
  • Извлеките первый элемент кучи и поместите его в качестве первого элемента нового списка.
  • Увеличьте оставшийся список.
  • Извлеките первый элемент новой кучи и поместите в качестве следующего элемента нового списка.
  • Повторяйте предыдущие шаги по порядку, пока список кучи не станет пустым. В конце новый список сортируется.

Вертикальная сортировка по временной сложности

Одноэтапный подход используется для определения временной сложности пирамидальной сортировки. Предположим, что нужно отсортировать 8 несортированных элементов.

Возможное максимальное количество операций для наполнения 8 элементы 8 .
возможное максимальное количество операций для нагромождения оставшихся 7 элементы 7 .
возможное максимальное количество операций для нагромождения оставшихся 6 элементы 6 .
возможное максимальное количество операций для нагромождения оставшихся 5 элементы 5 .
возможное максимальное количество операций для нагромождения оставшихся 4 элементы 4 .
возможное максимальное количество операций для нагромождения оставшихся 3 элементы 3 .
возможное максимальное количество операций для нагромождения оставшихся два элементы два .
возможное максимальное количество операций для нагромождения оставшихся 1 элемент 1 .

Возможное максимальное количество операций:

8 + 7 + 6 + 5 + 4 + 3 + два + 1 знак равно 36

Среднее число этих операций равно:

36 / 8 знак равно 4,5

Обратите внимание, что последние четыре кучи на предыдущей иллюстрации не изменились, когда был удален первый элемент. Некоторые из предыдущих куч также не изменились при удалении первого элемента. При этом лучшее среднее количество основных операций (перестановок) 3, а не 4,5. Итак, лучшее общее среднее количество основных операций:

24 знак равно 8 Икс 3
=> 24 знак равно 8 Икс журнал < суб > два < / суб > 8

так как журнал два 8 = 3.

В целом, средняя временная сложность случая для пирамидальной сортировки составляет:

О ( н. log2n )

Где точка означает умножение, а n — это N, общее количество элементов в списке (любом списке).

Обратите внимание, что операция извлечения первого элемента была проигнорирована. Что касается временной сложности, то операции, которые занимают относительно короткое время, игнорируются.

Кодирование на С++

В библиотеке алгоритмов C++ есть функция make_heap(). Синтаксис:

шаблон < учебный класс Итератор случайного доступа, учебный класс Сравнивать >
constexpr пустота make_heap ( RandomAccessIterator первым, RandomAccessIterator последним, сравнить комп. ) ;

Он принимает итератор, указывающий на первый элемент вектора, в качестве первого аргумента, а затем итератор, указывающий сразу за концом вектора, в качестве последнего аргумента. Для предыдущего несортированного списка синтаксис будет использоваться следующим образом, чтобы получить минимальную кучу:

вектор < инт > ВТР знак равно { 9 , 19 , 24 , 5 , 3 , одиннадцать , 14 , 22 , 7 , 6 , 17 , пятнадцать } ;
вектор < инт > :: итератор iterB знак равно втр. начинать ( ) ;
вектор < инт > :: итератор iterE знак равно втр. конец ( ) ;
make_heap ( iterB, iterE, больше < инт > ( ) ) ;

Этот код изменяет содержимое вектора на минимальную конфигурацию кучи. В следующих векторах C++ вместо двух массивов будут использоваться два вектора.

Чтобы скопировать и вернуть первый элемент вектора, используйте векторный синтаксис:

constexpr опорный фронт ( ) ;

Чтобы удалить первый элемент вектора и выбросить его, используйте векторный синтаксис:

constexpr стереть итератор ( const_iterator позиция )

Чтобы добавить элемент в конец вектора (следующий элемент), используйте векторный синтаксис:

constexpr пустота отталкивать ( константа Т & Икс ) ;

Начало программы такое:

#include <иопоток>
#include <алгоритм>
#include <вектор>
с использованием пространство имен станд. ;

Алгоритм и векторные библиотеки включены. Далее в программе идет функция heapsort(), а именно:

пустота сортировка кучей ( вектор < инт > & старыйV, вектор < инт > & новыйV ) {
если ( старый В. размер ( ) > 0 ) {
вектор < инт > :: итератор iterB знак равно старый В. начинать ( ) ;
вектор < инт > :: итератор iterE знак равно старый В. конец ( ) ;
make_heap ( iterB, iterE, больше < инт > ( ) ) ;

инт следующий знак равно старый В. фронт ( ) ;
старый В. стереть ( iterB ) ;
новыйВ. отталкивать ( следующий ) ;
сортировка кучей ( старый В, новый В ) ;
}
}

Это рекурсивная функция. Он использует функцию make_heap() библиотеки алгоритмов C++. Второй сегмент кода в определении функции извлекает первый элемент из старого вектора после построения кучи и добавляет его в качестве следующего элемента для нового вектора. Обратите внимание, что в определении функции векторные параметры являются ссылками, а функция вызывается с идентификаторами (именами).

Подходящей основной функцией С++ для этого является:

инт главный ( инт аргк, уголь ** argv )
{
вектор < инт > старый V знак равно { 9 , 19 , 24 , 5 , 3 , одиннадцать , 14 , 22 , 7 , 6 , 17 , пятнадцать } ;
вектор < инт > новыйV ;
сортировка кучей ( старый В, новый В ) ;

за ( инт я знак равно 0 ; я < новыйВ. размер ( ) ; я ++ ) {
cout << новыйV [ я ] << ' ' ;
}
cout << конец ;

возвращаться 0 ;
}

Результат:

3 5 6 7 9 одиннадцать 14 пятнадцать 17 19 22 24

отсортировано (полностью).

Вывод

В статье подробно обсуждались природа и функции Heap Sort, широко известного как Heapsort, как алгоритма сортировки. Heapify Time Complexity, иллюстрация Heapsort и Heapsort как алгоритм были рассмотрены и подкреплены примерами. Средняя временная сложность хорошо написанной программы пирамидальной сортировки составляет O(nlog(n))