Бинарная пирамидальная сортировка

Алгоритмы сортировки

Цель лекции: изучить основные алгоритмы внутренних сортировок и научиться решать задачи сортировок массивов различными методами (бинарная пирамидальная сортировка, метод Шелла, быстрая сортировка Хоара, сортировка слиянием).

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

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

Алгоритмом сортировки называется алгоритм для упорядочения некоторого множества элементов. Обычно под алгоритмом сортировки подразумевают алгоритм упорядочивания множества элементов по возрастанию или убыванию.

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

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

Практически каждый алгоритм сортировки можно разбить на 3 части:

· сравнение, определяющее упорядоченность пары элементов;

· перестановку, меняющую местами пару элементов;

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

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

Оценка алгоритмов сортировки

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

· Время сортировки – основной параметр, характеризующий быстродействие алгоритма.

· Память – один из параметров, который характеризуется тем, что ряд алгоритмов сортировки требуют выделения дополнительной памяти под временное хранение данных. При оценке используемой памяти не будет учитываться место, которое занимает исходный массив данных и независящие от входной последовательности затраты, например, на хранениекода программы.

· Устойчивость – это параметр, который отвечает за то, что сортировка не меняет взаимного расположения равных элементов.

· Естественность поведения – параметр, которой указывает на эффективность метода при обработке уже отсортированных, или частично отсортированных данных. Алгоритм ведет себя естественно, если учитывает эту характеристику входной последовательности и работает лучше.

Классификация алгоритмов сортировок

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

Наиболее подробно рассмотрим классификацию алгоритмов сортировки по сфере применения. В данном случае основные типы упорядочивания делятся следующим образом.

· Внутренняя сортировка – это алгоритм сортировки, который в процессе упорядочивания данных использует только оперативную память (ОЗУ) компьютера. То есть оперативной памяти достаточно для помещения в нее сортируемого массива данных с произвольным доступом к любой ячейке и собственно для выполнения алгоритма. Внутренняя сортировка применяется во всех случаях, за исключением однопроходного считывания данных и однопроходной записи отсортированных данных. В зависимости от конкретного алгоритма и его реализации данные могут сортироваться в той же области памяти, либо использовать дополнительную оперативную память.

· Внешняя сортировка – это алгоритм сортировки, который при проведении упорядочивания данных использует внешнюю память, как правило, жесткие диски. Внешняя сортировка разработана для обработки больших списков данных, которые не помещаются в оперативную память. Обращение к различным носителям накладывает некоторые дополнительные ограничения на данный алгоритм: доступ к носителю осуществляется последовательным образом, то есть в каждый момент времени можно считать или записать только элемент, следующий за текущим; объем данных не позволяет им разместиться в ОЗУ.

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

Следует отметить, что внутренняя сортировка значительно эффективней внешней, так как на обращение к оперативной памяти затрачивается намного меньше времени, чем к носителям.

Рассмотрим основные алгоритмы внутренних сортировок, которые называются усовершенствованными (логарифмическими).

Бинарная пирамидальная сортировка

Данный метод сортировки был предложен Дж. У. Дж. Уильямсом и Р.У. Флойдом в 1964 году. Пирамидальная сортировка в некотором роде является модификацией такого подхода, как сортировка выбором, с тем лишь отличием, что минимальный (или максимальный) элемент из неотсортированной последовательности выбирается за меньшее количество операций. Для такого быстрого выбора из этой неотсортированной последовательности строится некоторая структура. Именно суть данного метода и состоит в построении такой структуры, которая называется пирамидой.

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

Просеивание – это построение новой пирамиды по следующему алгоритму: новый элемент помещается в вершину дерева, далее он перемещается ("просеивается") по пути вниз на основе сравнения с дочерними элементами. Спуск завершается, если результат сравнения с дочерними элементами соответствует ключу сортировки.

Последовательность чисел xi,xi+1,...,xn формирует пирамиду, если для всех k=i, i+1,...,n/2 выполняются неравенстваxk > x2k, xk > xi (или xk < x2k, xk < x2k+1 ). Элементы x2i и x2i+1 называются потомками элемента xi.

Массив чисел 12 10 7 5 8 7 3 является пирамидой. Такой массив удобно изображать в виде дерева. Первый элемент массива, элементы которого образуют собой пирамиду, является наибольшим (или наименьшим). Если массив представлен в видепирамиды, то массив легко отсортировать.

Алгоритм пирамидальной сортировки.

Шаг 1. Преобразовать массив в пирамиду (рис. 42.1. А).

Шаг 2. Использовать алгоритм сортировки пирамиды (рис. 42.1. В – H).

Алгоритм преобразования массива в пирамиду (построение пирамиды). Пусть дан массив x[1],x[2],...,x[n].

Шаг 1. Устанавливаем k=n/2.

Шаг 2. Перебираем элементы массива в цикле справа налево для i=k,k-1,...,1. Если неравенства xi > x2i, xi > x2i+1 не выполняются, то повторяем перестановки xi с наибольшим из потомков. Перестановки завершаются при выполнении неравенствxi > x2i, xi > x2i+1.

Алгоритм сортировки пирамиды.

Рассмотрим массив размерности n, который представляет пирамиду x[1],x[2],...,x[n].

Шаг 1. Переставляем элементы x[1] и x[n].

Шаг 2. Определяем n=n-1. Это эквивалентно тому, что в массиве из дальнейшего рассмотрения исключается элемент x[n].

Шаг 3. Рассматриваем массив x[1],x[2],...,x[n-1], который получается из исходного за счет исключения последнего элемента. Данный массив из-за перестановки элементов уже не является пирамидой. Но такой массив легко преобразовать впирамиду. Это достигается повторением перестановки значения элемента из x[1] с наибольшим из потомков. Такая перестановка продолжается до тех пор, пока элемент из x[1] не окажется на месте элемента x[i] и при этом будут выполняться неравенства x[i] > x[2i], x[i] > x[2i+1]. Тем самым определяется новое место для значения первого элемента из x[1] (рис. 1. С).

Шаг 4. Повторяем шаги 2, 3, 4 до тех пор, пока не получим n=1. Произвольный массив можно преобразовать в пирамиду (рис. 1. ).

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

Построение пирамиды, ее сортировка и "просеивание" элементов реализуются с помощью рекурсии. Базой рекурсии при этом выступает пирамида из одного элемента, а сортировка и просеивание элементов сводятся посредством декомпозиции к аналогичным действиям с пирамидой из n-1 элемента.

//Описание функции бинарной пирамидальной сортировкиvoid Binary_Pyramidal_Sort (int k,int *x){ Build_Pyramid(k/2+1,k-1,x); Sort_Piramid(k-1,x);} //Построение пирамидыvoid Build_Pyramid (int k, int r, int *x){ Sifting(k,r,x); if (k > 0) Build_Pyramid(k-1,r,x);} //Сортировка пирамидыvoid Sort_Piramid (int k, int *x){ Exchange (0,k,x); Sifting(0,k-1,x); if (k > 1) Sort_Piramid(k-1,x);} //"Просеивание" элементовvoid Sifting (int left, int right, int *x){ int q, p, h; q=2*left+1; p=q+1; if (q <= right){ if (p <= right && x[p] > x[q])       q = p; if (x[left] < x[q]){ Exchange (left, q, x); Sifting(q, right, x); } }}//процедура обмена двух элементовvoid Exchange (int i, int j, int *x){  int tmp; tmp = x[i]; x[i] = x[j]; x[j] = tmp;}

Теоретическое время работы этого алгоритма можно оценить, учитывая, что пирамидальная сортировка аналогична построениюпирамиды методом просеивания (при этом не учитывается начальное построение пирамиды). Поэтому время работы алгоритма пирамидальной сортировки без учета времени построения пирамиды будет определяться по формуле T1(n)=O(nxlog n).

Построение пирамиды занимает T2(n)=O(n) операций за счет того, что реальное время выполнения функции построения зависит от высоты уже созданной части пирамиды.

Тогда общее время сортировки (с учетом построения пирамиды) будет равно: T(n)=T1(n)+T2(n)=O(n)+O(nxlog n)=O(nxlog n).

Пирамидальная сортировка не использует дополнительной памяти. Метод не является устойчивым: по ходу работы массив так "перетряхивается", что исходный порядок элементов может измениться случайным образом. Поведение неестественно: частичная упорядоченность массива никак не учитывается. Данная сортировка на почти отсортированных массивах работает также долго, выигрыш ее получается только на больших n.

Сортировка методом Шелла

Сортировка Шелла была названа в честь ее изобретателя – Дональда Шелла, который опубликовал этот алгоритм в 1959 году. Общая идея сортировки Шелла состоит в сравнении на начальных стадиях сортировки пар значений, расположенных достаточно далеко друг от друга в упорядочиваемом наборе данных. Такая модификация метода сортировки позволяет быстро переставлять далекие неупорядоченные пары значений (сортировка таких пар обычно требует большого количества перестановок, если используется сравнение только соседних элементов).

Общая схема метода состоит в следующем.

Шаг 1. Происходит упорядочивание элементов n/2 пар (xi,xn/2+i) для 1<i<n/2.

Шаг 2. Упорядочиваются элементы в n/4 группах из четырех элементов (xi,xn/4+i,xn/2+i,x3n/4+i) для 1<i<n/4.

Шаг 3. Упорядочиваются элементы уже в n/4 группах из восьми элементов и т.д.

На последнем шаге упорядочиваются элементы сразу во всем массиве x1,x2,...,xn. На каждом шаге для упорядочивания элементов в группах используется метод сортировки вставками ( рис. 42.2).

В настоящее время неизвестна последовательность hi,hi-1,hi-2,...,h1,, оптимальность которой доказана. Для достаточно больших массивов рекомендуемой считается такая последовательность, что hi+1=3hi+1, а h1=1. Начинается процесс с hm, что hm>[n/9]. Иногда значение h вычисляют проще: hi+1=hi/2,h1=1,hm=n/2. Это упрощенное вычисление h и будем использовать далее.


Рис. 42.2. Демонстрация сортировки по неубыванию методом Шелла

//Описание функции сортировки Шеллаvoid Shell_Sort (int n, int *x){ int h, i, j; for (h = n/2 ; h > 0 ; h = h/2) for (i = 0 ; i < n-h ; i++) for (j = i ; j >= 0 ; j = j - h)   if (x[j] > x[j+h])           Exchange (j, j+h, x);   else j = 0;}//процедура обмена двух элементовvoid Exchange (int i, int j, int *x){ int tmp; tmp = x[i]; x[i] = x[j]; x[j] = tmp;}

Метод, предложенный Дональдом Л. Шеллом, является неустойчивой сортировкой по месту.

Эффективность метода Шелла объясняется тем, что сдвигаемые элементы быстро попадают на нужные места. Среднее время для сортировки Шелла равняется O(n1.25), для худшего случая оценкой является O(n1.5).

Быстрая сортировка Хоара

Метод быстрой сортировки был впервые описан Ч.А.Р. Хоаром в 1962 году. Быстрая сортировка – это общее название ряда алгоритмов, которые отражают различные подходы к получению критичного параметра, влияющего на производительность метода.

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

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

Алгоритм быстрой сортировки Хоара

Пусть дан массив x[n] размерности n.

Шаг 1. Выбирается опорный элемент массива.

Шаг 2. Массив разбивается на два – левый и правый – относительно опорного элемента. Реорганизуем массив таким образом, чтобы все элементы, меньшие опорного элемента, оказались слева от него, а все элементы, большие опорного – справа от него.

Шаг 3. Далее повторяется шаг 2 для каждого из двух вновь образованных массивов. Каждый раз при повторении преобразования очередная часть массива разбивается на два меньших и т. д., пока не получится массив из двух элементов (рис. 42.3).

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

Выберем в качестве опорного элемент, расположенный на средней позиции.


Рис. 42.3. Демонстрация быстрой сортировки Хоара по неубыванию

//Описание функции сортировки Хоараvoid Hoar_Sort (int k, int *x){ Quick_Sort (0, k-1, x);} void Quick_Sort(int left, int right, int *x){ int i, j, m, h; i = left; j = right; m = x[(i+j+1)/2]; do { while (x[i] < m) i++; while (x[j] > m) j--; if (i <= j) { Exchange(i,j,x); i++; j--; } } while(i <= j); if (left < j)     Quick_Sort (left, j, x); if (i < right)     Quick_Sort (i, right, x);} //процедура обмена двух элементовvoid Exchange (int i, int j, int *x){ int tmp; tmp = x[i]; x[i] = x[j]; x[j] = tmp;}

Эффективность быстрой сортировки в значительной степени определяется правильностью выбора опорных (ведущих) элементов при формировании блоков. В худшем случае трудоемкость метода имеет ту же сложность, что и пузырьковая сортировка, то есть порядка O(n2). При оптимальном выборе ведущих элементов, когда разделение каждого блока происходит на равные по размеру части, трудоемкость алгоритма совпадает с быстродействием наиболее эффективных способов сортировки, то есть порядка O(n log n). В среднем случае количество операций, выполняемых алгоритмом быстрой сортировки, определяется выражениемT(n) = O(1.4n log n)

Быстрая сортировка является наиболее эффективным алгоритмом из всех известных методов сортировки, но все усовершенствованные методы имеют один общий недостаток – невысокую скорость работы при малых значениях n.

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

Сортировка слиянием

Алгоритм сортировки слиянием был изобретен Джоном фон Нейманом в 1945 году. Он является одним из самых быстрых способов сортировки.

Слияние – это объединение двух или более упорядоченных массивов в один упорядоченный.

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

Данный алгоритм применяется тогда, когда есть возможность использовать для хранения промежуточных результатов память, сравнимую с размером исходного массива. Он построен на принципе "разделяй и властвуй". Сначала задача разбивается на несколько подзадач меньшего размера. Затем эти задачи решаются с помощью рекурсивного вызова или непосредственно, если их размер достаточно мал. Далее их решения комбинируются, и получается решение исходной задачи ( рис. 42.4).

Процедура слияния требует два отсортированных массива. Заметим, что массив из одного элемента по определению является отсортированным.

Алгоритм сортировки слиянием

Шаг 1. Разбить имеющиеся элементы массива на пары и осуществить слияние элементов каждой пары, получив отсортированные цепочки длины 2 (кроме, быть может, одного элемента, для которого не нашлось пары).

Шаг 2. Разбить имеющиеся отсортированные цепочки на пары, и осуществить слияние цепочек каждой пары.

Шаг 3. Если число отсортированных цепочек больше единицы, перейти к шагу 2.


Рис. 42.4. Демонстрация сортировки слиянием по неубыванию

//Описание функции сортировки слияниемvoid Merging_Sort (int n, int *x){ int i, j, k, t, s, Fin1, Fin2; int* tmp = new int[n]; k = 1; while (k < n){ t = 0; s = 0; while (t+k < n){ Fin1 = t+k; Fin2 = (t+2*k < n ? t+2*k : n); i = t;       j = Fin1; for ( ; i < Fin1 && j < Fin2 ; s++){   if (x[i] < x[j]) {     tmp[s] = x[i];     i++;   }   else {     tmp[s] = x[j];     j++;   } } for ( ; i < Fin1; i++, s++)   tmp[s] = x[i]; for ( ; j < Fin2; j++, s++)    tmp[s] = x[j]; t = Fin2; } k *= 2; for (s = 0; s < t; s++) x[s] = tmp[s]; } delete(tmp);}

Недостаток алгоритма заключается в том, что он требует дополнительную память размером порядка n (для хранения вспомогательного массива). Кроме того, он не гарантирует сохранение порядка элементов с одинаковыми значениями. Но его временная сложность всегда пропорциональна O(n log n).

Ключевые термины

Алгоритм сортировки – это алгоритм для упорядочения некоторого множества элементов.

Бинарная пирамидальная сортировка – это алгоритм внутренней сортировки, основанный на построении пирамиды и просеивании элементов из ее вершины методом спуска вниз в соответствии с ключом сортировки.

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

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

Внутренняя сортировка – это алгоритм сортировки, который в процессе упорядочивания данных использует толькооперативную память (ОЗУ) компьютера.

Время сортировки – основной параметр трудоемкости алгоритма, характеризующий быстродействие алгоритма сортировки.

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

Ключ сортировки – это атрибут (или несколько атрибутов), по значению которого определяется порядок элементов во множестве.

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

Память – один из параметров трудоемкости алгоритма, который характеризует размер выделяемой дополнительной памяти под временное хранение данных.

Пирамида (сортирующее дерево, двоичная куча) – это двоичное дерево с упорядоченными листьями, в корне которого расположен максимальный или минимальный элемент.

Просеивание – это построение новой пирамиды посредством спуска вниз элемента из вершины дерева в соответствии с ключом сортировки

Слияние – это объединение двух или более упорядоченных массивов в один упорядоченный.

Сортировка слиянием – это одна из разновидностей алгоритмов быстрых сортировок, основанная на слиянии подмножеств массива.

Сортировка Хоара – это одна из разновидностей быстрых сортировок, основанная на упорядочивании подмножеств массива относительно опорных элементов.

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

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

Краткие итоги

1. Сортировка является одной из фундаментальных алгоритмических задач программирования.

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

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

4. По сфере применения алгоритмы сортировок классифицируются на алгоритмы внутренних и внешних сортировок.

5. Бинарная пирамидальная сортировка является алгоритмом внутренней сортировки, основанном на построении пирамиды и просеивании элементов из ее вершины методом спуска вниз в соответствии с ключом сортировки

6. Пирамидальная сортировка не использует дополнительной памяти. Метод не является устойчивым. Поведение неестественно. Данная сортировка на почти отсортированных массивах работает также долго, выигрыш ее получается только на больших n.

7. Сортировка Шелла является алгоритмом внутренней сортировки, основанном на сравнении и перемещении пар значений, расположенных сначала достаточно далеко друг от друга в упорядочиваемом наборе данных, с дальнейшим сокращением расстояний между ними.

8. Сортировка Шелла является неустойчивой сортировкой по месту. Эффективность метода Шелла объясняется тем, что сдвигаемые элементы быстро попадают на нужные места.

9. Сортировка Хоара является одной из разновидностей быстрых сортировок, основанная на упорядочивании подмножеств массива относительно опорных элементов.

10. Эффективность быстрой сортировки в значительной степени определяется правильностью выбора опорных элементов при формировании блоков.

11. Сортировка слиянием является одним из самых простых алгоритмов сортировки среди быстрых алгоритмов, который может быть эффективно использован для сортировки связанных списков.

12. Недостаток алгоритма сортировки слиянием заключается в том, что он требует дополнительную память размером порядкаn, не гарантирует сохранение порядка элементов с одинаковыми значениями. Его временная сложность всегда пропорциональна O(n log n).

13. Быстрая сортировка является наиболее эффективным алгоритмом из всех известных методов сортировки, но все усовершенствованные методы имеют один общий недостаток – невысокую скорость работы при малых значениях n.


Дата добавления: 2021-01-21; просмотров: 114; Мы поможем в написании вашей работы!

Поделиться с друзьями:




Мы поможем в написании ваших работ!