Cортировка слиянием с использованием O(1) дополнительной памяти — различия между версиями
Строка 1: | Строка 1: | ||
− | После того, как мы научились сливать с использованием <tex> O(1) </tex> дополнительной памяти и <tex> O(n) </tex> операций , оставшееся решение задачи становится очевидным. Будем сливать не рекурсивно, чтобы сэкономить память в стеке. Пусть на i-том шаге у нас отсортированы подряд идущие, не пересекающиеся куски массива размером <tex> 2^i </tex>(за исключением последнего, его размер может быть меньше). Тогда сольем сначала первый и второй кусок, потом третий и четвертый и так до последнего. Если последнему куску нету пары, то просто ничего не делаем. Выполняем это для всех i от 2 до <tex> \lceil ln(n) \rceil </tex> | + | После того, как мы научились сливать с использованием <tex> O(1) </tex> дополнительной памяти и <tex> O(n) </tex> операций , оставшееся решение задачи становится очевидным. Будем сливать не рекурсивно, чтобы сэкономить память в стеке. Пусть на i-том шаге у нас отсортированы подряд идущие, не пересекающиеся куски массива размером <tex> 2^i </tex>(за исключением последнего, его размер может быть меньше). Тогда сольем сначала первый и второй кусок, потом третий и четвертый и так до последнего. Если последнему куску нету пары, то просто ничего не делаем. Выполняем это для всех i от <tex> 2 </tex> до <tex> \lceil ln(n) \rceil </tex> |
==Алгоритм слияние == | ==Алгоритм слияние == | ||
Строка 19: | Строка 19: | ||
Пример : | Пример : | ||
− | Пусть длины групп равны трем и | + | Пусть длины групп равны трем и <tex> x_1<y_1<x_2<x_3<y_3 </tex>, где первая группа <tex> x_1,x_2,x_3 </tex> , а вторая <tex> y_1,y_2,y_3. </tex> |
{| border="1" | {| border="1" | ||
Строка 27: | Строка 27: | ||
|- | |- | ||
|1 | |1 | ||
− | |[ | + | |<tex>[x_1,x_2,x_3,y_1,y_2,y_3,a_1,a_2,a_3] </tex> |
− | |[ | + | |<tex>[a_1,a_2,a_3,y_1,y_2,y_3,x_1,x_2,x_3] </tex> |
|- | |- | ||
|2 | |2 | ||
− | |[ | + | |<tex>[a_1,a_2,a_3,y_1,y_2,y_3,x_1,x_2,x_3] </tex> |
− | |[ | + | |<tex>[x_1,a_2,a_3,y_1,y_2,y_3,a_1,x_2,x_3] </tex> |
|- | |- | ||
|3 | |3 | ||
− | |[ | + | |<tex>[x_1,a_2,a_3,y_1,y_2,y_3,a_1,x_2,x_3] </tex> |
− | |[ | + | |<tex>[x_1,y_1,a_3,a_2,y_2,y_3,a_1,x_2,x_3] </tex> |
|- | |- | ||
|4 | |4 | ||
− | |[ | + | |<tex>[x_1,y_1,a_3,a_2,y_2,y_3,a_1,x_2,x_3] </tex> |
− | |[ | + | |<tex>[x_1,y_1,x_2,a_2,y_2,y_3,a_1,a_3,x_3] </tex> |
|- | |- | ||
|5 | |5 | ||
− | |[ | + | |<tex>[x_1,y_1,x_2,a_2,y_2,y_3,a_1,a_3,x_3] </tex> |
− | |[ | + | |<tex>[x_1,y_1,x_2,y_2,a_2,y_3,a_1,a_3,x_3] </tex> |
|- | |- | ||
|6 | |6 | ||
− | |[ | + | |<tex>[x_1,y_1,x_2,y_2,a_2,y_3,a_1,a_3,x_3] </tex> |
− | |[ | + | |<tex>[x_1,y_1,x_2,y_2,x_3,y_3,a_1,a_3,a_2] </tex> |
|} | |} | ||
Строка 56: | Строка 56: | ||
=== Шаг 4 === | === Шаг 4 === | ||
− | Пусть размер остатка s. Начиная с конца, разобьем наш массив на подряд идущие группы длиной s. Используя квадратичную или более быструю сортировку, которая требует дополнительной памяти <tex> O(1) </tex>, отсортируем подмассив длиной 2s, который находится в конце. На последних s местах будут находится s максимальных элементов. Оставшаяся часть представляет собой массив, содержащий две отсортированные части, причем размер второй равен s. По аналогии с шагом 3 в обратном порядке сливаем группы длиной s. | + | Пусть размер остатка <tex> s </tex>. Начиная с конца, разобьем наш массив на подряд идущие группы длиной s. Используя квадратичную или более быструю сортировку, которая требует дополнительной памяти <tex> O(1) </tex>, отсортируем подмассив длиной <tex> 2s </tex>, который находится в конце. На последних <tex> s </tex> местах будут находится s максимальных элементов. Оставшаяся часть представляет собой массив, содержащий две отсортированные части, причем размер второй равен<tex> s </tex>. По аналогии с шагом 3 в обратном порядке сливаем группы длиной <tex> s </tex>. |
Количество операций на этом шаге <tex> O(n) </tex>. | Количество операций на этом шаге <tex> O(n) </tex>. |
Версия 22:40, 15 июня 2011
После того, как мы научились сливать с использованием
дополнительной памяти и операций , оставшееся решение задачи становится очевидным. Будем сливать не рекурсивно, чтобы сэкономить память в стеке. Пусть на i-том шаге у нас отсортированы подряд идущие, не пересекающиеся куски массива размером (за исключением последнего, его размер может быть меньше). Тогда сольем сначала первый и второй кусок, потом третий и четвертый и так до последнего. Если последнему куску нету пары, то просто ничего не делаем. Выполняем это для всех i от доСодержание
Алгоритм слияние
На вход алгоритм получает массив, который состоит из двух отсортированных кусков. На выходе алгоритм возвращает отсортированный массив. Алгоритм состоит из нескольких шагов.
Шаг 1
Разобьем наш массив на группы подряд идущих элементов длиной
. Остаток трогать не будем. Найдем группу, содержащую конец первого отсортированного куска. Поменяем ее с последней. Добавим последнюю группу в остаток.Количество операций на этом шаге
.Шаг 2
Возьмем и отсортируем группы по первому элементу (в случае равенства по последнему). Это можно сделать любой квадратичной или более быстрой сортировкой, которая требует дополнительной памяти
, например сортировка выбором. Следует заметить, что, после сортировки этих групп, элементы, которые стоят левее заданного и больше его, находились в противоположном куске отсортированного массива, также они находятся в пределах одной группы, поэтому количество инверсий для каждого элемента не больше .Так как кусков
, количество операций на этом шаге .Шаг 3
Попытаемся слить первую и вторую группу. Поменяем местами первую группу и часть остатка. И, как в обычном слиянии, пользуясь двумя указателями, сливаем вторую группу и только что измененную часть остатка. Результат начинаем записывать с начала первой группы. Чтобы ничего не перезаписалось, вместо записи используем обмен элементов. Так как группы имеют одинаковую длину, и между указателем на вторую группу и указателем на запись расстояние равно длине группы, то слияние произойдет корректно.
Пример : Пусть длины групп равны трем и
, где первая группа , а втораяНомер операции | Массив до выполнения операции | Массив после выполнения операции |
---|---|---|
1 | ||
2 | ||
3 | ||
4 | ||
5 | ||
6 |
Потом аналогично сольем вторую и третью группу и так до последней группы. Так как после второго шага количество инверсий для каждого элемента не больше
, то ему надо сдвинутся влево не больше, чем на элементов, поэтому в конце, не учитывая остаток, массив будет отсортированный.Количество групп
, и каждое слияние работает за , поэтому количество операций на этом шаге .Шаг 4
Пусть размер остатка
. Начиная с конца, разобьем наш массив на подряд идущие группы длиной s. Используя квадратичную или более быструю сортировку, которая требует дополнительной памяти , отсортируем подмассив длиной , который находится в конце. На последних местах будут находится s максимальных элементов. Оставшаяся часть представляет собой массив, содержащий две отсортированные части, причем размер второй равен . По аналогии с шагом 3 в обратном порядке сливаем группы длиной .Количество операций на этом шаге
.Шаг 5
Опять, используя экономную по памяти, хотя и квадратичную, сортировку, отсортируем:
- остаток и первую группу.
- последнюю группу.
Не стоит забывать, что после новой разметки остаток находится в начале, а не в конце.
В результате массив будет отсортированным
Количество операций на этом шаге
.