mirror of
https://github.com/Steffo99/appunti-magistrali.git
synced 2024-11-25 11:34:18 +00:00
102 lines
2.5 KiB
Markdown
102 lines
2.5 KiB
Markdown
|
# Merge sort
|
||
|
|
||
|
Il _merge sort_ è una soluzione **ricorsiva** all'ordinamento per confronto.
|
||
|
|
||
|
## Funzionamento
|
||
|
|
||
|
Per questo algoritmo, utilizziamo la tecnica del **divide et impera**.
|
||
|
|
||
|
1. _Divide_: Divido A in **due parti**.
|
||
|
2. _Impera_: Metto **separatamente in ordine** le parti.
|
||
|
3. _Unisci_: **Unisco** le due parti.
|
||
|
|
||
|
Consideriamo come **caso base** della ricorsione una parte composta da un numero, che ovviamente è già ordinata con sè stessa.
|
||
|
|
||
|
### Merge
|
||
|
|
||
|
Per **unire le due parti** usiamo una funzione detta `merge()`.
|
||
|
|
||
|
Costruiamo una nuova sequenza uguale alla sequenza 1, ma **aggiungiamo alla fine un valore sentinella** sempre maggiore di tutti gli elementi contenuti.
|
||
|
|
||
|
> ```
|
||
|
> | 1 | 3 | 7 | 8 | ∞ |
|
||
|
> ```
|
||
|
|
||
|
Facciamo **la stessa cosa** per la sequenza due.
|
||
|
|
||
|
> ```
|
||
|
> | 2 | 4 | 5 | 6 | ∞ |
|
||
|
> ```
|
||
|
|
||
|
Prendo i primi numeri delle due sequenze e **metto il più piccolo nella sequenza iniziale**.
|
||
|
|
||
|
> ```
|
||
|
> | 1 | 2 | 3 | | | | | |
|
||
|
> | | | 7 | 8 | ∞ |
|
||
|
> | | 4 | 5 | 6 | ∞ |
|
||
|
> ```
|
||
|
|
||
|
**Continuo** finchè non ho messo tutti i numeri; **grazie alla sentinella non usciremo mai dalla sequenza**, in quanto essa è sempre maggiore di tutti gli altri numeri.
|
||
|
|
||
|
> ```
|
||
|
> | 1 | 2 | 3 | 4 | 5 | 6 | | |
|
||
|
> | | | 7 | 8 | ∞ |
|
||
|
> | | | | | ∞ |
|
||
|
> ```
|
||
|
|
||
|
Quando **rimangono solo le sentinelle** significa che abbiamo aggiunto tutti gli elementi, e quindi abbiamo finito.
|
||
|
|
||
|
> ```
|
||
|
> | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
||
|
> | | | | | ∞ |
|
||
|
> | | | | | ∞ |
|
||
|
> ```
|
||
|
|
||
|
|
||
|
## Costo computazionale
|
||
|
|
||
|
| Categoria | Upper bound | Lower bound | Tight bound |
|
||
|
|-----------|-------------|-------------|-------------|
|
||
|
| Tempo | `O(n log n)` | `Ω(n log n)` | **`θ(n log n)`** |
|
||
|
|
||
|
Il merge sort è un algoritmo ricorsivo con un **caso base in tempo costante** e che **richiama sè stesso 2 volte**.
|
||
|
|
||
|
```latex
|
||
|
T(n) =\\
|
||
|
\\
|
||
|
Θ(1) \qquad n=1\\
|
||
|
2 T(\frac{n}{2}) + Θ(n) \qquad n \neq 1
|
||
|
```
|
||
|
|
||
|
Applicando il **caso particolare del Master Theorem**, otteniamo:
|
||
|
|
||
|
```latex
|
||
|
T(n) =\\
|
||
|
\\
|
||
|
Θ(1) \qquad n=1\\
|
||
|
Θ(n log n) \qquad n \neq 1
|
||
|
```
|
||
|
|
||
|
## Pseudocodice
|
||
|
|
||
|
```python
|
||
|
def merge_sorted(part):
|
||
|
# Caso base
|
||
|
if len(part) == 1:
|
||
|
return part
|
||
|
# Divide
|
||
|
middle = len(part) // 2
|
||
|
part_a = part[:middle]
|
||
|
part_b = part[middle:]
|
||
|
# Impera
|
||
|
sort_a = merge_sorted(part_a)
|
||
|
sort_b = merge_sorted(part_b)
|
||
|
# Combina
|
||
|
return merge(sort_a, sort_b)
|
||
|
```
|
||
|
|
||
|
## Visualizzazione
|
||
|
|
||
|
[hackerearth.com](https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/visualize/)
|
||
|
|
||
|
[visualgo.net](https://visualgo.net/bn/sorting) (Nota: visualizza solo la fase _Unisci_ del sort)
|