Merge sort je jeden z najefektívnejších triediacich algoritmov, má časovú zložitosť O(n log n). Jeho úspech spočíva v použití stratégie rozdeľovania a panovania. Jeho rekurzívna povaha a efektívna stratégia zlúčenia robia z neho efektívne riešenie pre triedenie veľkých dátových množín.
Postup algoritmu
- Rozdeľovanie: Zoznam sa rozdelí na polovicu, a to opakovane, až kým nie sú vytvorené jednoprvkové podzoznamy.
- Zlúčenie (Merge): Jednoprvkové podzoznamy sa zlúčia tak, aby vznikol nový zoznam. Pri tomto zlúčení sa zároveň zabezpečí, že prvky v novom zozname sú utriedené.
def merge_sort(zoznam):
if len(zoznam) > 1:
stred = len(zoznam) // 2 # celočíselné delenie
lavy = zoznam[:stred]
pravy = zoznam[stred:]
merge_sort(lavy)
merge_sort(pravy)
zjednotenie_zoznamov(lavy, pravy)
1. Rozdeľovanie
merge_sort
je rekurzívna funkcia, ktorá rozdeľuje zoznam a volá sa na oba vzniknuté podzoznamy.
2. Zjednotenie zoznamov
Funkcia zjednotenia zoznamov je kľúčovým prvkom v programe, ktorý zabezpečuje spojenie a zoradenie dvoch utriedených zoznamov. Využíva indexy pre postupné porovnávanie prvkov v oboch zoznamoch, pričom do výsledného zoznamu pridá ten menší z dvoch.
Verzia č. 1 funkcie pre zjednotenie zoznamov
def zjednotenie_zoznamov(zoznam1, zoznam2):
# Inicializácia prázdneho výsledného zoznamu
# a indexov pre oba zoznamy
vysledny_zoznam = []
i = 0
j = 0
# zjednotenie zoznamov
while i < len(zoznam1) and j < len(zoznam2):
# Porovnanie prvkov na aktuálnych pozíciách v oboch zoznamoch
if zoznam1[i] < zoznam2[j]:
vysledny_zoznam.append(zoznam1[i])
i += 1
else:
vysledny_zoznam.append(zoznam2[j])
j += 1
# Pridanie zvyšných prvkov z neukončených zoznamov
while i < len(zoznam1):
vysledny_zoznam.append(zoznam1[i]) ; i += 1
while j < len(zoznam2):
vysledny_zoznam.append(zoznam2[j]) ; j += 1
return vysledny_zoznam
Verzia č. 2 funkcie pre zjednotenie zoznamov
def zjednotenie_zoznamov(zoznam1, zoznam2):
# Inicializácia prázdneho výsledného zoznamu
# a indexov pre oba zoznamy
vysledny_zoznam = []
i = 0
j = 0
# While cyklus s podmienkou závislou od súčtu dĺžok oboch zoznamov
while i < len(zoznam1) + len(zoznam2):
# Porovnanie prvkov na aktuálnych pozíciách v oboch zoznamoch
if i < len(zoznam1) and (j >= len(zoznam2) or zoznam1[i] < zoznam2[j]):
vysledny_zoznam.append(zoznam1[i])
i += 1
else:
vysledny_zoznam.append(zoznam2[j])
j += 1
return vysledny_zoznam
Časová zložitosť
Priemerný aj najhorší prípad má zložitosť O ( n log n ).
Keď delíme zoznam na polovicu, jeho veľkosť sa zredukuje na polovicu (n/2). Po ďalšom delení sa veľkosť zoznamu zredukuje na (n/2)/2= n/22, a tak ďalej. Počet delení potrebných na to, aby sme dosiahli zoznam veľkosti 1, je log2 n. Preto je časová zložitosť rozdeľovania na polovicu O(log2 n).
Časová zložitosť lúčenia je O ( n ), čo sa aplikuje pre každú rozdelenú časť, teda O ( log n ) x O ( n )