ricorsione è più intuitivo da cui io preferisco lo stesso, tranne in alcune situazioni quando voglio evitare una profondità dello stack significativa (ad es. durante il consumo di determinate implementazioni di co-routine). In caso di Merge sort comunque la versione iterativa è in realtà più facile da seguire (almeno lo pseudo codice).
Tutto ciò che serve è un ciclo nidificato con il ciclo interno che esegue l'unione su coppie di elementi 2^k con il ciclo esterno responsabile dell'incremento di k.
Un ulteriore passaggio necessario è quello di unire qualsiasi gruppo non abbinato con il gruppo unito precedente. Un gruppo non abbinato si incontrerà se il numero di elementi non è un potere di 2. Un gruppo non abbinato sarà sempre alla fine dell'iterazione.
ad es. [5, 7, 3, 4, 1, 9] -> [5, 7] [3, 4] [1, 9] -> [3, 4, 5, 7] [1, 9] -> [ 1, 3, 4, 5, 7, 9]
Nell'esempio precedente [1, 9] è un gruppo che non aveva un altro gruppo da unire inizialmente. Così è stato fuso con il gruppo precedente (che si era fusa e ordinati già)
Ecco un'implementazione pitone:
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
ho usato la funzione di fusione dalla versione normale (ricorsiva). Mentre il codice sopra non è il più elegante, ma funziona e ha la stessa complessità della versione ricorsiva.(Non ho controllato a fondo, ma sembra così a me da una rapida occhiata)
Ecco una prova di unità:
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
Considerate le risposte qui: http://stackoverflow.com/questions/2171517/ attuare-a-Mergesort-senza-using-un-ulteriore-array – Marcin