Lezione 10: 11 Febbraio 2014
Transcript
Lezione 10: 11 Febbraio 2014
Tutorato di Algoritmi e Strutture Dati [CT0371] Lezione 10: 11 Febbraio 2014 Tutor: Alberto Carraro Disclaimer: Queste note non sono state sottoposte al consueto controllo riservato alle pubblicazioni ufficiali. Esse dunque possono essere distribuite al di fuori di queste lezioni solo con il permesso del docente. In questa lezione rivediamo gli argomenti visti a lezione nelle settimane precedenti: • Insertion Sort • Merge Sort • Quick Sort Esercizio 1 (Appello del 26/01/2012, parte II) Modificare la funzione PARTITION del quicksort per ottenere una funzione PARTITION’(A,p,r) che permuta gli elementi di A[p . . . r] e restituisce due indici q e t con p ≤ q ≤ t ≤ r tali che a. ogni elemento di A[p . . . q − 1] sia minore di A[q] b. tutti gli elementi di A[q . . . t] siano uguali c. ogni elemento di A[t + 1 . . . r] sia maggiore di A[q] Come PARTITION, anche PARTITION’ dovrà richiedere un tempo Θ(r − p). Dimostrare la correttezza di PARTITION’ definendo un’invariante di ciclo. Svolgimento: Consideriamo l’algoritmo quicksort dato in [[]Cap. 7]CLRS. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 PARTITION’(A,p,r){ x = A[r] t = p-1 q = p-1 for (j=p; j<= r-1; j++){ if (A[j] < x){ q++ exchange A[q] with A[j] t++ exchange A[t] with A[j] } if (A[j] == x){ t++ exchange A[t] with A[j] } } exchange A[t+1] with A[r] return (q,t) } 10-1 10-2 Lezione 10: 11 Febbraio 2014 Che PARTITION’ abbia complessità temporele Θ(r − p) è evidente, perché il ciclo for esegue r − p operazioni di complessità costante. Diamo un’invariante per il ciclo for. Invariante: all’inizio di ogni iterazione del ciclo for per ogni indice k (1) se p ≤ k ≤ q allora A[k] < x; (2) se q + 1 ≤ k ≤ t, allora A[k] = x; (3) se t + 1 ≤ k ≤ j − 1, allora A[k] > x; (4) se k = r, allora A[k] = x. Inizializzazione: prima della prima iterazione del ciclo, q = t = p − 1 e j = p. Siccome non vi sono valori in [p, q] né in [q + 1, t] né in [t + 1, j − 1], le condizioni (1),(2) e (3) sono trivialmente soddisfatte. La condizione (4) vale grazie al primo assegnamento. Mantenimento: Se A[j] > x allora l’unica operazione effettuata è j = j + 1. Dopo l’incremento di j la condizione (3) vale perché A[j − 1] e tutte le altre celle rimangono invariate. Se A[j] = x allora viene fatto t = t + 1, si scambiano tra loro A[t] e A[j] ed infine si fa j = j + 1. Grazie allo scambio, ora A[t] = x e la condizione (2) vale. Similmente A[j − 1] > x perché l’elemento scambiato con A[j] (prima dell’incremento di j) è, per l’invariante, maggiore di x. Se A[j] < x allora viene fatto q = q + 1, e si scambiano tra loro A[q] e A[j]; quindi dopo l’incremento j = j + 1 rimane vero che A[q] < x (come per tutti gli elementi a sinistra di A[q]). Inotre si fa t = t + 1 e poi si scambiano tra loro A[t] e A[j]; siccome in A[j] c’era un elemento uguale a x ora resta vero che A[t] = x (come per tutti gli elementi a sinistra di A[q]) e la condizione (2) vale. Similmente A[j − 1] > x perché l’elemento A[t] (dopo l’incremento di t) scambiato con A[j] (prima dell’incremento di j) è, per l’invariante > x. Terminazione: alla terminazione del ciclo abbiamo j = r quindi ogni cella dell’array rientra in una delle quattro casistiche dell’invariante ed abbiamo partizionato tutto l’array da destra a sinistra in elementi < x, elementi uguali a x ed elementi maggiori di x. Esercizio 2 (Appello del 15/05/2012, parte II) Dato un array non ordinato di n interi, eventualmente ripetuti, progettare un algoritmo efficiente che restituisca il numero di elementi che occorrono una sola volta e analizzarne la complessità in tempo. L’algoritmo deve utilizzare spazio aggiuntivo costante e devono essere definite esplicitamente eventuali funzioni/procedure ausiliarie. Svolgimento: Per utilizzare spazio costante applichiamo l’ordinamento quicksort all’array (che ordina inplace in maniera crescente). Ora che l’array è ordinato ci possiamo applicare il seguente algoritmo COUNT(A){ c = 0 i = 1 while (i <= n){ j = i while (A[i] == A[j] && i <= n) j++ if (j==i+1) c++ i = j } return c Lezione 10: 11 Febbraio 2014 10-3 La complessità temporale di COUNT è Θ(n), quindi in totale il nostro algoritmo ha complessità O(n2 ) anche se in media è Θ(n + n log n). Esercizio 3 (Appello del 16/07/2010, parte II) Dato un vettore A di n interi non necessariamente distinti, si dice che un elemento è di maggioranza se appare in A almeno d n2 e volte. Scrivere due funzioni di complessità in spazio aggiuntivo costante e in tempo a. Θ(n2 ) b. Θ(n log n) per stabilire se A contiene un elemento di maggioranza, e in caso affermativo lo restituisca. Svolgimento: COUNT(A){ b = false i = 1 while (i <= n){ j = i while (A[i] == A[j] && i <= n) j++ if (j-i >= n/2 ) b = true i = j } return b References [1] C. Demetrescu, I. Finocchi, G.F. Italiano, Algoritmi e strutture dati 2/ed. McGraw-Hill, 2008. [2] T.H. Cormen, C.E. Leiserson, R.L. Rivest, C. Stein, Introduzione agli algoritmi e strutture dati 3/ed, McGraw-Hill, 2010.