Одним классическим примером алгоритма "разделяй и властвуй" является сортировка слиянием.
Существует два подхода реализации сортировки слиянием "сверху вниз" и "снизу вверх". Первый вариант можно просто реализовать с использованием рекурсии. Задача сортировки слиянием ставится и решается следующим образом:
- Дан неотсортированный список, например список чисел. Требуется отсортировать список в порядке возрастания или убывания.
- На первом шаге разделим данный список на два
- На следующем шаге рекурсивно отсортируем два списка, полученные на первом шаге. В процессе рекурсии сортируемые
списки будут становиться все меньше, пока не станут пустыми или не будут состоять из одного элемента. Это будет базой рекурсии. - Наконец мы объединяем отсортированные списки, полученные на предыдущем шаге.
Алгоритм сортировки слиянием представлен ниже.
Итак, после разбиения двух списков необходимо провести слияние. Сложность этого шага будет O(n), где n - общее количество элементов в двух списках. Слияние реализуется с использованием двух указателей и дополнительного списка
Реализация сортировки слиянием на python:
def merge_sort(nums):
"""
Сортировка
"""
# Базовый случай
if len(nums) <= 1:
return nums
# Разделяем
pivot = int(len(nums) / 2)
# Рекурсивно решаем более простую задачу
left_list = merge_sort(nums[0:pivot])
right_list = merge_sort(nums[pivot:])
# Объединяем
return merge(left_list, right_list)
def merge(left_list, right_list):
"""
Слияние
"""
left_cursor = right_cursor = 0
ret = []
while left_cursor < len(left_list) and right_cursor < len(right_list):
if left_list[left_cursor] < right_list[right_cursor]:
ret.append(left_list[left_cursor])
left_cursor += 1
else:
ret.append(right_list[right_cursor])
right_cursor += 1
ret.extend(left_list[left_cursor:])
ret.extend(right_list[right_cursor:])
return ret
В подходе "снизу вверх", мы делим список на подсписки по 1 элементу и затем рекурсивно объединяем их уже известным нам способом.
Реализация сортировки слиянием методом снизу вверх выглядит следующим образом:
from collections import deque
def merge_sort(nums):
"""
Sort
"""
# Divide and conquer
res = deque([[i] for i in nums])
# Merge
while len(res) > 1:
one = res.popleft()
two = res.popleft()
res.append(merge(one, two))
return res[0]
def merge(left_list, right_list):
"""
Merge
"""
left_cursor = right_cursor = 0
ret = []
while left_cursor < len(left_list) and right_cursor < len(right_list):
if left_list[left_cursor] < right_list[right_cursor]:
ret.append(left_list[left_cursor])
left_cursor += 1
else:
ret.append(right_list[right_cursor])
right_cursor += 1
ret.extend(left_list[left_cursor:])
ret.extend(right_list[right_cursor:])
return ret