Рекурсия более интуитивна, поэтому я предпочитаю то же самое, за исключением некоторых ситуаций, когда я хочу избежать значительной глубины стека (например, при использовании определенных реализаций сопрограммы). В случае сортировки слиянием, однако, итеративная версия на самом деле легче следовать (по крайней мере, псевдокод).
Все, что нужно, - это вложенный цикл, в котором внутренний цикл выполняет слияние пар из 2 ^ k элементов, а внешний цикл отвечает за увеличение k.
Требуется дополнительный шаг - объединить любую непарную группу с предыдущей объединенной группой. Непарная группа будет встречаться, если число элементов не является степенью 2. Непарная группа всегда будет в конце итерации.
например.
[5, 7, 3, 4, 1, 9] -> [5, 7] [3, 4] [1, 9] -> [3, 4, 5, 7] [1, 9] -> [1 , 3, 4, 5, 7, 9]
В приведенном выше примере [1, 9] - это группа, в которой не было другой группы, с которой нужно было изначально объединиться. Таким образом, он был объединен с предыдущей группой (которая уже была объединена и отсортирована)
Вот реализация Python:
from MergeSort import merge
def sort(arr):
n = len(arr) - 1
c = 1
start = 0
mid = 0
end = 0
while c <= n:
while end < n:
mid = start + c//2
end = start + c
if (start < n) and (end <= n):
merge(arr, start, mid, end)
start = end + 1
else:
merge(arr, start - c - 1, start-1, n)
c = 2*c + 1
start = 0
mid = 0
end = 0
Я использовал функцию слияния из обычной (рекурсивной) версии. Хотя приведенный выше код не самый элегантный, но он работает и имеет ту же сложность, что и рекурсивная версия. (Я не проверил подробно, но мне так кажется с первого взгляда)
Вот модульный тест:
def test_merge_sort_iterative(self):
for i in range(1, 100):
length = randint(10, 5000)
data = [randint(1, 10000) for x in range(1, length)]
IterativeMergeSort.sort(data)
issorted = True
i = 0
while (i < len(data) - 1) & issorted:
if data[i] > data[i + 1]:
issorted = False
i += 1
self.assertTrue(issorted, data)
return