Опубликован: 26.09.2006 | Уровень: специалист | Доступ: платный
Лекция 4:

Приоритетные очереди

< Лекция 3 || Лекция 4: 123456 || Лекция 5 >

Бесхитростная сортировка в памяти с прямым доступом.

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

\formula{
\t for\ {k}:= 1\ \t to\ n - 1\ \t do
for\ i:= k+ 1\
\t to\ n\ \t do\ \t if\ {\rm
key}[{i}] < {\rm key}[{k}]\ \t then\ {\rm tr}({i},{k});
}

Здесь {\rm tr}({i},{k}) — процедура, транспонирующая элементы {\rm key}[{i}],\, {\rm key}[{k}]. Заметим, что число сравнений

\eq*{
"{\rm key}[{i}] < {\rm key}[{k}]"
}
при реализации такого алгоритма равно n(n - 1)/2. В частности, это означает, что время работы алгоритма равно O(n^2).

Сортировка методом "разделяй и властвуй".

Предположим, что в нашем распоряжении имеется процедура РАЗДЕЛЯЙ (i, j, k), которая по заданным значениям индексов i, j находит некоторое промежуточное значение k и переставляет элементы сегмента {\rm key}[i \ldots j] так, чтобы для s = {i},\,{i} +
1,\,\ldots,\,{k} - 1 выполнялось неравенство {\rm key}[{s}] \le {\rm key}[k], а для s = k + 1,\, k + 2,\, \ldots, j — неравенство {\rm key}[{k}] \le {\rm key}[{s}].

Тогда для сортировки сегмента {\rm key}[{i} \ldots {j}] может быть использована рекурсивная процедура СОРТИРУЙ.

\formula{
\t{procedure СОРТИРУЙ}\ (i,
j);\\
\t begin\ \t if\ {i} = {j}\ \t then\ \t{exit}\
\t else\\
\mbox{}\q \t{РАЗДЕЛЯЙ}\ ({i}, {j}, {k});\ \t{СОРТИРУЙ}\ (i, k - 1);\
\t{СОРТИРУЙ}\ (k + 1, j)\}\\
\t end;
}

Для сортировки всего исходного массива достаточно выполнить оператор СОРТИРУЙ (1, n).

Заметим, что если бы процедура РАЗДЕЛЯЙ работала линейное от длины сегмента время и давала значение k, близкое к середине между i и j, то число обращений к ней приблизительно равнялось бы \log n и сортировка всего массива проходила бы за время порядка O(n \cdot \log n). Однако можно доказать, что при естественной реализации эта оценка справедлива лишь в среднем.

Упражнения

  1. Разработайте вариант процедуры СОРТИРУЙ без использования рекурсии. Сколько дополнительной памяти требуется для запоминания границ еще не отсортированных сегментов?
  2. Охарактеризуйте работу процедуры СОРТИРУЙ на заранее отсортированном массиве.
  3. Напишите на известном вам алгоритмическом языке программу сортировки числового массива с помощью процедуры СОРТИРУЙ и испытайте ее на массивах, сгенерированных с помощью датчика случайных чисел.
  4. Составьте таблицу, отражающую время работы вашей программы на массивах разной длины. Каков максимальный размер массива, который можно отсортировать составленной программой на вашем компьютере?

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

Этот метод является разновидностью метода "разделяй и властвуй"; впрочем, уместнее было бы назвать его "властвуй и объединяй".

Предположим, что у нас есть процедура СЛИВАЙ ( i, j, k), которая два уже отсортированных сегмента {\rm key}[{i}\ldots (j -
1)] и {\rm key}[{j}\ldots {k}] преобразует (сливает) в один сегмент {\rm key}[{i}\ldots {k}], делая его полностью отсортированным. Тогда рекурсивная процедура

\formula{
\t{procedure СОРТИРУЙ}\ (i,
j);\\
\t begin\ \t{if}\ {i} = {j}\
\t then\ \t{exit}\ \t else\\
\mbox{}\q \{m:= (i + j)\ \t div\ 2;\
\t{СОРТИРУЙ}\ (i, m);\
\t{СОРТИРУЙ}\ (m+1, j);\\
\mbox{}\q \t{СЛИВАЙ} (i, m, j)\}\\
\t end;
}

очевидно, сортирует сегмент {\rm key}[{i}\ldots {j}], а для сортировки всего исходного массива достаточно выполнить оператор СОРТИРУЙ (1, n). Как видим, вопрос балансировки размера сегментов решается здесь просто. Число обращений к процедуре СЛИВАЙ (i, m, j) равно \log n, а время ее выполнения легко сделать линейным от суммарной длины сливаемых сегментов.

Упражнения

  1. Разработайте процедуру СЛИВАЙ и вариант процедуры СОРТИРУЙ без использования рекурсии. Сколько дополнительной памяти требуется для ее реализации?
  2. Оцените теоретически время работы алгоритма по методу слияния.
  3. Напишите на известном вам алгоритмическом языке программу сортировки числового массива методом слияния и испытайте ее на массивах, сгенерированных с помощью датчика случайных чисел.
  4. Составьте таблицу, отражающую время работы вашей программы на массивах разной длины. Каков максимальный размер массива, который можно отсортировать составленной программой на вашем компьютере?

Сортировка с помощью d-кучи.

Для представления сортируемой последовательности используем структуру d-кучи. Сортировку можно провести в два этапа. Данный алгоритм (heapsort) работает для бинарных деревьев (d=2) и это необходимо указывать

  1. Окучить сортируемый массив, применяя последовательно операцию ПОГРУЖЕНИЕ по очереди к узлам (n - 1),\, (n - 2),\, \ldots,\, 0 в предположении, что сначала все n ключей занимают в произвольном порядке массив {\rm key}[0 \ldots n - 1].
  2. Осуществить окончательную сортировку следующим образом. Первый (минимальный) элемент кучи меняем местами с последним, уменьшаем размер кучи на 1 (минимальный элемент остается в последней позиции массива {\rm key}, не являясь уже элементом кучи) и применяем операцию ПОГРУЖЕНИЕ к корню, затем повторяем аналогичные действия, пока размер кучи не станет равным 1.

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

\formula{
\t{procedure SORT}(n);\\
\t begin\ \t{for}\ i:= n - 1\
\t downto\ 0\
\t do\ \t{ПОГРУЖЕНИЕ}\ (i);\\
\mbox{}\q \t while\ n > 1\
\t do\ \{{\rm tr} (1, n);\
n:= n - 1;\ \t{ПОГРУЖЕНИЕ} (1)\}\\
\t end;
}

Заметим, что процедура SORT не требует дополнительной памяти, размер которой зависел бы от длины массива \rm key.

Упражнения

  1. Докажите, что оператор
    \eq*{
\t for\ i := n - 1\ \t downto\ 0\ \t do\
\t{ПОГРУЖЕНИЕ}\ (i);
}

    в процедуре SORT можно заменить оператором

    \eq*{
\t for\ i := n \t div\ 2\ \t downto\ 0\ \t do\
\t{ПОГРУЖЕНИЕ}\ (i).
  2. Напишите программу сортировки числового массива с помощью процедуры {\rm SORT}(n) и испытайте ее на массивах, сгенерированных с помощью датчика случайных чисел. Составьте таблицу, отражающую время работы вашей программы на массивах разной длины. Каков максимальный размер массива, который можно отсортировать составленной программой на вашем компьютере?
< Лекция 3 || Лекция 4: 123456 || Лекция 5 >
Антон Сиротинкин
Антон Сиротинкин

на стр 6, лекции 3, Очевидно "Ck <= модуль(Gk(е))*b(k+1)" (1) - , подскажите что значит "модуль" и почему это очевидно...
 

Дмитрий Степаненко
Дмитрий Степаненко
Россия
Эдуард Санин
Эдуард Санин
Украина, Харьков, ХАИ