Сортировка слиянием
Содержание
Описание
Сортировка слиянием — алгоритм сортировки, хороший пример использования принципа «разделяй и властвуй». Он был предложен Джоном фон Нейманом в 1945 году.
Это стабильный алгоритм сортировки, использующий
дополнительной памяти и времени.Принцип работы
Принцип «разделяй и властвуй» — сначала задача разбивается на несколько подзадач меньшего размера. Затем эти задачи решаются с помощью рекурсивного вызова или непосредственно, если их размер достаточно мал. Наконец, их решения комбинируются, и получается решение исходной задачи.
Процедура слияния требует два отсортированных массива. Заметив, что массив из одного элемента по определению является отсортированным, мы можем осуществить сортировку следующим образом:
- Разбить имеющиеся элементы массива на пары и осуществить слияние элементов каждой пары, получив отсортированные цепочки длины 2 (кроме, быть может, одного элемента, для которого не нашлось пары).
- Разбить имеющиеся отсортированные цепочки на пары, и осуществить слияние цепочек каждой пары.
- Если число отсортированных цепочек больше единицы, перейти к шагу 2.
Слияние двух массивов
Допустим, у нас есть два отсортированных массива А и B размерами
и соответственно, и мы хотим объединить их элементы в один большой отсортированный массив C размером . Для этого можно применить процедуру слияния, суть которой заключается в повторяющемся «отделении» элемента, наименьшего из двух имеющихся в началах исходных массивов, и присоединении этого элемента к концу результирующего массива. Элементы мы переносим до тех пор, пока один из исходных массивов не закончится. После этого оставшийся «хвост» одного из входных массивов дописывается в конец результирующего массива. Пример работы процедуры показан на рисунке:
Алгоритм слияния формально можно записать следующим образом:
// слияние двух массивов с помощью временного merge(array a, int left, int middle, int right) // left - левая граница, right - правая, middle - середина array b = a[middle + 1, right]; i = left, j = middle + 1, k = 0; array temp; while i <= middle and j <= right temp[k++] = (a[j] < b[i]) ? a[j++] : b[i++]; while i <= middle temp[k++] = b[i++]; while j <= right temp[k++] = a[j++]; for (int t = 0; t != k; t++) a[t] = temp[t] // в конце a[1..k] это будет отсортированный массив
Рекурсивный алгоритм
Проще всего формализовать этот алгоритм рекурсивным способом. Функция сортирует участок массива от элемента с номером left до элемента с номером right:
sort(array a, int left, int right) // right и left — правая и левая граница массива, middle — середина middle = right / 2 if middle == right // условие выхода — если массив стал состоять из 1 элемента return sort(a, left, middle) sort (a, middle + 1, right) merge(array a, left, middle, right)
Пример работы алгоритма показан на рисунке:
Время работы
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай
( — это время, необходимое на то, чтобы слить два массива). Распишем это соотношение:
Осталось оценить
. Мы знаем, что , а значит . Уравнение примет вид . Так как — константа, то .