1 / 22

Vedremo in seguito che  ( n log n ) è un limite stretto per il problema dell’ordinamento.

Vedremo in seguito che  ( n log n ) è un limite stretto per il problema dell’ordinamento. Per ora ci limitiamo a dimostrare che:

tod
Download Presentation

Vedremo in seguito che  ( n log n ) è un limite stretto per il problema dell’ordinamento.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Vedremo in seguito che (n log n) è un limite stretto per il problema dell’ordinamento. Per ora ci limitiamo a dimostrare che: La complessità nel caso pessimo di ogni algoritmo di ordinamento sul posto che confronta e scambia tra loro soltanto elementi consecutivi dell’array è (n2). Quindi il problema di ordinare sul posto un array scambiando tra loro soltanto elementi consecutivi ha complessità (n2).

  2. Sia A[1..n] un array Se i < j e A[i] > A[j] diciamo che la coppia di indici (i, j) è una inversione i j k 8 3 3 Se l’array è ordinato non ci sono inversioni. Se l’array è ordinato in senso opposto e gli elementi sono tutti distinti allora ogni coppia (i, j) di indici con i < j è una inversione e quindi ci sono esattamente n(n-1)/2 inversioni.

  3. Come cambia il numero di inversioni quando facciamo uno scambio tra due elementi consecutivi A[i] ed A[i+1] dell’array? i i+1 x y Consideriamo tutte le coppie di indici ( j, k) con j < k e vediamo quante e quali di esse possono cambiare di stato da inversioni a non inversioni o viceversa quando scambiamo A[i] con A[i+1].

  4. Se j e k sono entrambi diversi da i e i+1 la coppia ( j, k) non cambia di stato e quindi il numero di inversioni di questo tipo non cambia. j i i+1 k u y x v

  5. Consideriamo le due coppie (i, k) e (i+1, k) con k > i+1 ossia i i+1 k x y v i i+1 k y x v (i, k) è inversione dopo lo scambio se e solo se (i+1, k) lo era prima e (i+1, k) è inversione se e solo se (i, k) lo era prima. Quindi le due coppie si scambiano gli stati ma il numero totale di inversioni non cambia.

  6. Consideriamo le coppie (j, i) e (j,i+1) con j < i ossia j i i+1 u x y j i i+1 u y x La situazione è simmetrica di quella precedente e quindi anche in questo caso il numero totale di inversioni non cambia.

  7. Rimane soltanto da considerare la coppia (i, i+1) che con lo scambio cambia di stato se i due elementi sono diversi. In conclusione con lo scambio di due elementi consecutivi dell’array il numero totale di inversioni aumenta o diminuisce di 1 (o rimane invariato se i due elementi scambiati erano uguali).

  8. Nel caso pessimo in cui l’array è ordinato in senso inverso e gli elementi sono tutti distinti le inversioni iniziali sono n(n-1)/2. Occorrono quindi almeno n(n-1)/2 scambi tra elementi consecutivi per ridurre tale numero a 0. Siccome n(n-1)/2 = (n2) rimane dimostrato il limite inferiore.

  9. Esercizio: Abbiamo dimostrato che scambiando due elementi diversi consecutivi il numero totale di inversioni aumenta o diminuisce di 1. Quindi se prima dello scambio il numero di inversioni totale era pari, dopo lo scambio esso risulta dispari e viceversa. Mostrare che questo cambiamento della parità del numero totale di inversioni avviene anche se si scambiano due elementi diversi non consecutivi.

  10. Abbiamo visto che la complessità nel caso pessimo di ogni algoritmo di ordinamento sul posto che confronta e scambia tra loro elementi consecutivi dell’array è (n2). Per ottenere algoritmi più efficienti dobbiamo quindi operare confronti e scambi tra elementi “distanti” dell’array. L’algoritmo Heap-Sort confronta elementi non consecutivi e possiamo quindi sperare che la sua complessità sia minore.

  11. Useremo le notazioni asintotiche anche all’interno delle formule. In questo caso le notazioni O(f(n)), Ω(f(n)) e ϴ(f(n)) stanno ad indicare una qualche funzione appartenente a tali insiemi e di cui non ci interessa conoscere la forma esatta ma solo il comportamento asintotico. Ad esempio T(n)=n2+O(n) significa che T(n) è la somma di n2 e di una funzione che cresce al più linearmente.

  12. Max-Heapfy(A,i) // Analisi: Complessità l=2i, r= 2i+1 m = i ifl A.heapsizeandA[l] > A[m] m=l ifr A.heapsizeandA[r] > A[m] m=r ifmi t=A[i], A[i] =A[m], A[m] =t Max-Heapfy(A,m)

  13. Build-Max-Heap (A) A.heapsize=A.length fori=A.lenght/2downto 1 Max-Heapfy(A,i)

  14. Heap-Sort(A) Build-Max-Heap(A) fori=A.lengthdownto 2 t=A[i], A[i] =A[1], A[1] =t A.heapsize = A.heapsize - 1 Max-Heapfy(A,1)

  15. f(x) f(n) f(n-1) f(n) f(n-2) f(n-1) f(m+3) f(n-2) f(m+2) f(n-3) f(m+1) f(m) f(m+3) f(m+2) f(m+1) f(m) … x m-1 m m+1 m+2 m+3 m+4 n-3 n-2 n-1 n n+1 Valutazione di sommatorie (App. A del testo) f(x) funzione crescente

  16. f(x) f(n) f(n-1) f(n) f(n-2) f(n-1) f(m+3) f(n-2) f(m+2) f(m+1) f(m+4) f(m) f(m+3) f(m+2) f(m+1) f(m) … x m-1 m m+1 m+2 m+3 m+4 n-3 n-2 n-1 n n+1 f(x) funzione crescente

  17. f(x) funzione decrescente f(m) f(m+1) f(m) f(m+2) f(m+1) f(n-3) f(m+2) f(n-2) f(m+3) f(n-1) f(n) f(n-3) f(n-2) f(x) f(n-1) … f(n) x m-1 m m+1 m+2 m+3 n-3 n-2 n-1 n n+1

  18. f(x) funzione decrescente f(m) f(m+1) f(m) f(m+2) f(m+1) f(n-3) f(m+2) f(n-2) f(n-1) f(n-2) f(n) f(n-2) f(n-2) f(x) f(n-1) … f(n) x m-1 m m+1 m+2 m+3 n-4 n-3 n-2 n-1 n n+1

  19. Dunque Heap-Sort richiede tempo O(n log n) per ordinare un array di nelementi.

  20. Implementazione di code con priorità Gli heap binari si possono usare, oltre che per ordinare un array, anche per implementare delle code con priorità. Le code con priorità sono delle strutture dati in cui è possibile immagazzinare degli oggetti x a cui è attribuita una priorità x.key ed estrarli uno alla volta in ordine di priorità.

  21. Le operazioni fondamentali sulle code con priorità sono: Insert(S, x): aggiunge x alla coda S Maximum(S): ritorna xS con x.key massima Extract-Max(S): toglie e ritorna xS con x.keymassima. • Possono inoltre essere definite anche: • Increase-Key(S,x,p): aumenta la priorità di x • Change-Key(S,x,p): cambia la priorità di x

More Related