5. Notazioni Asintotiche
(a) f(n) è stretta tra c1·g(n) e c2·g(n) Θ(g(n))
(b) f(n) è spinta sotto la funzione c·g(n) O(g(n))
(c) f(n) è spinta sopra la funzione c·g(n) Ω(g(n))
6. Notazioni Asintotiche
Θ(n)
Θ(n log n)
Θ(n2)
Θ(log n)
Gli ordini di grandezza identificano delle
CLASSI di COMPLESSITA’
Scrivere T(n)=O(log n) equivale a scrivere “correttamente” T(n) ∈ O(log n)
7. Notazioni Asintotiche
Notazioni grandi e notazioni piccole:
f(n)=O(g(n)) f(n) ≤ classe di g(n)
la notazione O-grande indica un limite superiore non strettola notazione O-grande indica un limite superiore non stretto
f(n)=o(g(n)) f(n) < classe di g(n)
la notazione O-piccola indica un limite superiore stretto
10. Ordinamento
La tecnica di ordinamento varia in base agli
elementi da ordinare:
- valori
- strutture/oggetti con attributo discriminante- strutture/oggetti con attributo discriminante
La tecnica di ordinamento varia in base alla
struttura contenitore:
- array / blocco di memoria ad accesso costante
- lista collegata di elementi
11. HeapSort
Basato su struttura Heap: albero binario con 2 proprietà
- Heap property: un nodo contiene un valore
maggiore dei sottoalberimaggiore dei sottoalberi
- shape property: albero completo tranne
ultimo livello
altezza dell’albero O(logn)
14. HeapSort
Operazione Heapify:
- input: nodo v dell’heap
(assunto: i sottoalberi sono heap)
- output: il sottoalbero su v è un heap
(il valore di v potrà essere scambiato con i valori
nei sottoalberi)
15. HeapSort
void heapify(int[] h, int i){
int sx=left(i);
int dx=right(i);
int m=indMax(h, sx, dx, i);
complessità:
O(logn)
applicato alla radice
int m=indMax(h, sx, dx, i);
if(i != m){
swapValue(h,i,m);
heapify(h,m)
}
}
16. HeapSort
void buildHeap(int[] h){
for(int i=h.length/2; i>=0; i--)
heapify(h,i);
}
complessità:
O(n)
analisi ammortizzata
}
Applico heapify a tutti i nodi con figli dell’heap.
Partendo dall’ultimo, fino al primo.
17. HeapSort
void heapSort(int[] h){
buildheap(h); O(n)
for(int i=h.length-1; i<=1;i--){ O(n)for(int i=h.length-1; i<=1;i--){ O(n)
swapValue(h,0,i); O(1)
heapify(h,0,i-1); O(logn)
}
}
Il terzo parametro nell’heapify diminuisce la dimensione.
Complessità: O(nlogn)
20. QuickSort
Metodo partition (versione di Hoare):
int partition(int[] a, int n1, int n2){
int x=a[n1];
int i=n1-1;
int j=n2+1;
while(true){
vettore a
Pivot
valori ≤
valori ≥
i j
while(true){
do j--; while(!(a[j]<=x));
do i++; while(!(a[i]>=x));
if(i<j)
swap(A,i,j);
else
return j;
}
}
22. Ordinamento
Algoritmo Peggiore Medio Migliore Memoria Stabile In Place
CountingSort O(n+k) O(n+k) O(n+k) O(n+k) SI NO
HeapSort O(nlogn) O(nlogn) O(nlogn) O(1) NO SI
QuickSort(2) O(nlogn) O(nlogn) O(nlogn) O(nlogn) NO SI
MergeSort O(nlogn) O(nlogn) O(nlogn) O(n) SI NO
SelectionSort O(n2) O(n2) O(n2) O(1) NO SISelectionSort O(n ) O(n ) O(n ) O(1) NO SI
InsertionSort O(n2) O(n2) O(n) O(1) SI SI
BubbleSort O(n2) O(n2) O(n) O(1) SI SI
QuickSort(1) O(n2) O(nlogn) O(nlogn) O(nlogn) NO SI
StupidSort Illimitato O(n*n!) O(n) O(n) NO SI
23. Ordinamento
java.util.Arrays.sort(…)
The sorting algorithm is a Dual-Pivot Quicksort by
Vladimir Yaroslavskiy, Jon Bentley, and JoshuaVladimir Yaroslavskiy, Jon Bentley, and Joshua
Bloch. This algorithm offers O(n log(n))
performance on many data sets that cause other
quicksorts to degrade to quadratic performance,
and is typically faster than traditional (one-pivot)
Quicksort implementations.
24. Ordinamento
OpenJDK: java.util.Arrays.sort(…)
private static void sort1(int x[], int off, int len) {
// Insertion sort on smallest arrays
if (len < 7) {
… }
// Choose a partition element, v
…
// Establish Invariant: v* (<v)* (>v)* v*
…
// Swap partition elements back to middle
…
// Recursively sort non-partition-elements
…
}
25. Ordinamento
java.util.Collections.sort(…)
• Implementation note: This implementation is a stable, adaptive, iterative mergesort that
requires far fewer than n lg(n) comparisons when the input array is partially sorted, while
offering the performance of a traditional mergesort when the input array is randomly
ordered. If the input array is nearly sorted, the implementation requires approximately n
comparisons. Temporary storage requirements vary from a small constant for nearly sorted
input arrays to n/2 object references for randomly ordered input arrays.
• The implementation takes equal advantage of ascending and descending order in its input• The implementation takes equal advantage of ascending and descending order in its input
array, and can take advantage of ascending and descending order in different parts of the
same input array. It is well-suited to merging two or more sorted arrays: simply concatenate
the arrays and sort the resulting array.
• The implementation was adapted from Tim Peters's list sort for Python (TimSort). It uses
techiques from Peter McIlroy's "Optimistic Sorting and Information Theoretic Complexity", in
Proceedings of the Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-
474, January 1993.
• This implementation dumps the specified list into an array, sorts the array, and iterates over
the list resetting each element from the corresponding position in the array. This avoids the
n2 log(n) performance that would result from attempting to sort a linked list in place.