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.