quicksort - marco frascafrasca.di.unimi.it/algm14/slides_lab7.pdf · ordini gli algoritmi heapsort,...
Post on 26-Jan-2019
263 Views
Preview:
TRANSCRIPT
QuickSort
● Algoritmo di ordinamento “sul posto” che ha tempo di esecuzione :
- O(n2) nel caso peggiore
- O(n log n) nel caso medio
● Nonostante le cattive prestazioni nel caso peggiore, rimane il miglior algoritmo di ordinamento in media
Università degli Studi di Milano
Marco Frasca
QuickSort
● È basato sulla metodologia Divide et Impera:● Dividi: L’array A[p…r] viene “partizionato” (tramite
spostamenti di elementi) in due sotto-array non vuoti A[p…q] e A[q+1…r] in cui:
● Impera: i due sottoarray A[p…q] e A[q+1…r] vengono ordinati ricorsivamente con QuickSort
● Combina: i sottoarray vengono ordinati separatamente, quindi non è necessaria alcuna combinazione. A[p…r] è già ordinato.
Università degli Studi di Milano
Marco Frasca
ogni elemento di A[p…q] è minore o uguale ad ogni ele-mento di A[q+1…r]
QuickSort
Quick-Sort(A,p,r)
IF p < r % base di ricorsione
THEN
q = Partiziona(A,p,r)
Quick-Sort(A, p, q)
Quick-Sort(A, q + 1, r)
Università degli Studi di Milano
Marco Frasca
Partiziona
Procedura Partiziona:
1. l’algoritmo sceglie un pivot, cioè l'elemento dell’array che fungerà da elemento di confine (per il suo valore e non per la posizione) tra i due sotto-array
2. Sposta i valori > pivot verso l’estremità destra dell’array e i valori < pivot verso quella sinistra.
3. La posizione di confine q dipenderà dal valore scelto come pivot: tale valore è la posizione in cui si troverà alla fine della procedura l’elemento più grande minore o uguale al pivot
Università degli Studi di Milano
Marco Frasca
Partiziona
Partiziona(A,p,r) x = A[p] i = p - 1 j = r + 1 WHILE true DO REPEAT j = j - 1
UNTIL A[j] x REPEAT i = i + 1
UNTIL A[i] x IF i < j THEN “scambia A[i] con A[j]” ELSE return j
Università degli Studi di Milano
Marco Frasca
Partiziona
La procedura Partiziona è quindi tale che:
● Se il numero di elementi dell’array minori o uguali all’elemento A[p], scelto come pivot, è pari a 1 (cioè A[p] è l’elemento minimo) (risp. n-1), allora le dimensioni delle partizioni restituite sono 1 per la partizione di sinistra e n - 1 per quella di destra (risp. n-1 e 1)
Università degli Studi di Milano
Marco Frasca
PartizionaUniversità degli Studi di Milano
Marco Frasca
Partiziona(A,p,r) x = A[p] i = p - 1 j = r + 1 WHILE true DO REPEAT j = j - 1
UNTIL A[j] x REPEAT i = i + 1
UNTIL A[i] x IF i < j THEN “scambia A[i] con A[j]” ELSE return j )(1
)(1
PartizionaUniversità degli Studi di Milano
Marco Frasca
Partiziona(A,p,r) x = A[p] i = p - 1 j = r + 1 WHILE true DO REPEAT j = j - 1
UNTIL A[j] x REPEAT i = i + 1
UNTIL A[i] x IF i < j THEN “scambia A[i] con A[j]” ELSE return j
)(n
)(1
QuickSort: analisi
● Il tempo di esecuzione di QuickSort dipende dal bilanciamento delle partizioni restituite dall’algoritmo partiziona
● Il caso migliore si verifica quando le partizioni sono perfettamente bilanciate, entrambe di dimensione n/2
● Il caso peggiore si verifica quando una partizione è sempre di dimensione 1 (la seconda è quindi di dimensione n - 1)
Università degli Studi di Milano
Marco Frasca
QuickSort: analisi
Caso Migliore:● le partizioni sono di uguale dimensione:
● T(n) = 2T(n/2) + (n)
- e per il caso 2 del teorema master: T(n) = (n log n)
Università degli Studi di Milano
Marco Frasca
QuickSort: analisi
Caso Peggiore:● La partizione sinistra ha sempre dimensione 1 mentre quella
sinistra ha sempre dimensione n – 1 (o viceversa):
-T(n) = T(1) + T(n - 1) + (n)
poiché T(1) = 1 otteniamo
-T(n) = T(n - 1) + (n)- L’equazione di ricorrenza può essere risolta facilmente col
metodo iterativo
-T(n) = T(n - 1) + (n) = (n2)
Università degli Studi di Milano
Marco Frasca
=∑k=1
n
Θ k = Θ∑k=1
n
k
QuickSort: analisi
Caso Medio:
● Si può mostrare che nel caso medio il QuickSort ha tempo di esecuzione (n log n), dove n è il numero di elementi da ordinare- Anche quando la bi-partizione risulta molto sbilanciata nella
maggior parte delle chiamate alla procedura Partiziona
Università degli Studi di Milano
Marco Frasca
QuickSort in Matlab
function A = quicksort(A, p, r)
% dispone in ordine crescente gli elementi del vettore x
% usando l’algoritmo "quicksort"
if p < r
[A q] = Partiziona(A, p, r);
if q >= p
A = quicksort(A, p, q);
A = quicksort(A, q + 1, r);
end
end
end
Università degli Studi di Milano
Marco Frasca
Partiziona in Matlab
function [x part]= partiziona(x, p, r)% esegue una partizione del vettore x. Pivot scelto primo elemento di x. p indice di
inzio, r indice di finepart = p-1; c = x(p); i = p; j = r;while 1 while x(i) < c i = i+1; end while x(j) > c j = j-1; end if i < j
w = x(i); x(i) = x(j); x(j) = w; i = i+1; j = j-1; else part=j; break; end endend
Università degli Studi di Milano
Marco Frasca
Esercizio
● Scrivere un script MATLAB che generi casualmente 4 vettori di 5000, 10000, 15000, 20000 interi compresi tra 1 e 1000000, li ordini gli algoritmi Heapsort, Insertion Sort e QuickSort , e stampi sullo stesso grafico i tempi di esecuzione di ciascun algoritmo su ogni vettore in input con tre colori differenti, tre simboli e tre linee differenti.
Università degli Studi di Milano
Marco Frasca
Struttura dati Dizionario
● Un dizionario è : un insieme di coppie (elemento, chiave) Sul campo chiave è definita una relazione d'ordine totale
● Operazioni:
● insert(elem e, chiave k)aggiunge ad S una nuova coppia (e, k)
● delete(elem e, chiave k)cancella da S la coppia con chiave k
● search(chiave k)se la chiave k è presente in s restituisce l’elemento e ad esso associato altrimenti
restituisce null● Le operazioni di inserimento e cancellazione rendono le
struttura dati dinamica
Università degli Studi di Milano
Marco Frasca
Struttura dati Dizionario:Vettore non ordinato
● Tengo traccia del numero n di elementi effettivamente presenti nel dizionario (dimensione logica dell’array)
● Insert: O(1) (inserisco in fondo all’array)
● Search: O(n) (devo scorrere l’array)
● Delete: O(n) (cerco l'elemento da cancellare e copio l’ultimo
elemento nella posizione cancellata)
● Lo stesso se usiamo una lista concatenata (ordinata o no)
Università degli Studi di Milano
Marco Frasca
Albero binario
● Un albero binario radicato è una coppia T = (N, A) costituita da un insieme N di nodi ed un insieme A N × N di coppie di ⊆nodi detti archi. In un albero:
1. Ogni nodo v (tranne la radice) ha un solo padre u tale che (u, v ) A. Nodi ∈
con lo stesso padre sono detti fratelli
2. Un nodo u può avere zero o uno o due figli (nodi v tali che (u, v) A) ∈
3. Un nodo senza figli è detto foglia, mentre i nodi che non sono né foglie né la
radice sono detti nodi interni
4. La profondità (o livello) di un nodo è dato dal numero di archi che bisogna
attraversare per raggiungerlo dalla radice
5. Altezza di un albero: massima profondità a cui si trova una foglia
Università degli Studi di Milano
Marco Frasca
Albero binario di ricerca
● Albero binario di ricerca (BST): albero binario in cui ogni nodo v contiene
a) un valore chiave(v) del dizionario
b) un campo padre parent(v)
c) un campo figlio sinistro sin(v)
d) un campo figlio destro des(v)
● Condizione:- Le chiavi nel sottoalbero sin(v) sono <= chiave(v)
- Le chiavi nel sottoalbero des(v) sono > chiave(v)
● Tali proprietà inducono un ordinamento totale sulle chiavi del dizionario
Università degli Studi di Milano
Marco Frasca
Albero binario di ricerca
Albero binario di ricerca Albero binario non di ricerca:
47 <= 49
Università degli Studi di Milano
Marco Frasca
!
Visita di un albero binario di ricerca
● Visita in ordine simmetrico – dato un nodo v, elenco prima 1) il sotto-albero sinistro di v (in ordine simmetrico), poi 2) il nodo v, poi 3) il sotto-albero destro di v (in ordine simmetrico)
● Visita_Inorder(radice del BST) visita tutti i nodi del BST una sola volta
● Complessità: T(n) = (n).
● Proprietà: Visita_Inorder visita i nodi del BST in ordine crescente rispetto alla chiave
Università degli Studi di Milano
Marco Frasca
algoritmo Visita_Inorder(node v)if (v null) then Visita_Inorder(sin(v)) stampa chiave(v) Visita_Inorder(des(v))
Albero binario di ricerca: ricerca
● Search(chiave k): traccia un cammino nell’albero partendo dalla radice: su ogni nodo, usa la proprietà del BST per decidere se proseguire nel sottoalbero sinistro o destro
● La complessità della procedura di ricerca considerata è T(n) = O(h), dove h è l’altezza del BST.
Università degli Studi di Milano
Marco Frasca
Albero binario di ricerca: inserimento
● Insert(chiave k): inserisce nell'albero un nuovo nodo u con chiave k. Cerca la chiave k nell’albero, identificando così il nodo v che diventerà padre del nodo u; tale nodo v deve essere un nodo dal quale la ricerca di k non può proseguire (e quindi deve essere un nodo v che non ha sottoalbero sinistro e/o destro)
● Crea un nuovo nodo u con chiave = k
● Appendi u come figlio sinistro/destro di v in modo che sia
mantenuta la proprietà di ordinamento totale
● La complessità della procedura considerata è T(n) = O(h), dove
h è l’altezza del BST
Università degli Studi di Milano
Marco Frasca
Albero binario di ricerca: predecessore
● Predecessor(chiave k): cerca il nodo v che ha la chiave che precede k nell'ordinamento delle chiavi (crescente).
- Sia u il nodo che contiene la chiave k● Caso 1. Esiste un sottoalbero sinistro di u.
- cerchiamo il predecessore nel sottoalbero sinistro di radice u
- non può essere nel sottoalbero del figlio destro (chiavi > k)
- Cerchiamo il max nel sottoalbero del figliosinistro
● si tratta del "nodo più a destra", individuabile scendendo sempre a destra in tale sottoalbero, fino a trovare un nodo senza figlio destro
Università degli Studi di Milano
Marco Frasca
u
v
w non qui
x
Albero binario di ricerca: predecessore
Predecessor(chiave k): cerca il nodo v che ha la chiave che precede k nell'ordinamento delle chiavi (crescente).
- Sia u il nodo che contiene la chiave k
Caso 2. Non esiste un sottoalbero sinistro di u
- cerchiamo il predecessore sul cammino verso la radice
- è il primo nodo con chiave minore di k che siincontra sul cammino verso la radice
- u deve essere nel sottoalbero sinistro di tale nodo
- Inoltre bisogna trovare quello più prossimo
- Basta risalire gli antenati di u finché troviamo un nodo figlio destro di suo padre v
Università degli Studi di Milano
Marco Frasca
u
v
Albero binario di ricerca: cancellazione
● Delete (chiave k): cerca la chiave k nell’albero, identificando così il nodo u con chiave k
1. Se u è una foglia, essa viene rimossa aggiornando il parent(u)
2. Il nodo u da eliminare ha un unico figlio f● Si elimina u e si attacca f a parent(u)
3. Il nodo u da eliminare ha due figli● Si individua il predecessore (risp. successore) v di u● Il predecessore (risp. successore) non ha figlio destro (risp. Sinistro)
● Perché se avesse figlio destro non sarebbe predecessore, perché il figlio destro avrebbe chiave < k ma maggiore di quella di v
● Si copia v in u e si rimuove v
Università degli Studi di Milano
Marco Frasca
Struttura dati Dizionario:Albero binario di ricerca Università degli Studi di Milano
Marco Frasca
● Oggetto BST in MATLABfunction listObject = BST(values) btree = struct('chiave',-1,'sin',-1,'des',-1, 'parent', -1); bdim = 0; root = -1; %indice della radice.-1 perché non ci sono ancora elementi bfree = []; % array che tiene traccia delle posizioni in btree % liberate da cancellazioni precedenti data = reshape(values,1,[]); % vettorizza i valori in values for i = 1:length(data) insert_bst(data(i)); end listObject = struct('insert',@insert_bst,...%handle di funzione 'delete',@delete_bst,... 'search',@search_bst,... 'size',@size_bst);
Struttura dati Dizionario:Albero binario di ricerca Università degli Studi di Milano
Marco Frasca
function id = search_bst(key) % metodo che restituisce l'indice id del nodo con chiave key. % cerca l'elemento di chiave key act = root; id = -1; % act == root, parto dalla radice while 1 if act < 0 % controllo, nodo foglia break; end if key > btree(act).chiave act = btree(act).des; else if key < btree(act).chiave act = btree(act).sin; else id = act; break; end end end end
Struttura dati Dizionario:Albero binario di ricerca Università degli Studi di Milano
Marco Frasca
function insert_bst(value) % metodo che inserisce nell'albero un nuovo nodo con chiave value % se non esiste già un nodo con chiave value if root == -1 root = 1; end % primo inserimento. Inizializzo anche root where = -1; act = root; % Se il nodo non è presente, where conterrà la posizione dove inserire if bdim > 0 while 1 % cerco la posizione dove inserire if act < 0 break; end % controllo, nodo foglia if value > btree(act).chiave where = act; act = btree(act).des; else if value < btree(act).chiave where = act; act = btree(act).sin; else break; end end end else % albero vuoto. Inserisco all'inizio del vettore where = 1; act = -1; endContinua …......
Struttura dati Dizionario:Albero binario di ricerca Università degli Studi di Milano
Marco Frasca
if act ~=-1 % Se non sono arrivato ad una foglia, allora il valore esisteva già disp('Elemento già presente'); else bdim = bdim + 1; if isempty(bfree) % se non ci sono posizioni libere id = bdim; % allora inserisco un nuovo elemento in coda all'array else % esistono già delle posizioni precedentemente liberate da cancellazioni id = bfree(1); bfree = bfree(2:numel(bfree)); % % scelgo la prima libera end v = struct('chiave',value,'sin',-1,'des',-1, 'parent', -1); if btree(where).chiave <=value % devo scegliere se il nodo deve essere figlio sinistro o destro btree(where).des = id; else btree(where).sin = id; end btree(id) = v; if(bdim > 1) % se è il primo nodo ad essere inserito, parent deve essere -1 btree(id).parent = where; else btree(id).parent = -1; end end end
Struttura dati Dizionario:Albero binario di ricerca Università degli Studi di Milano
Marco Frasca
function delete_bst(key) .
.
.
vedi file BST.m
end
end % end object
Esercizi
● Esercizio 1. Implementare la struttura dati dizionario utilizzando un vettore invece di un albero binario di ricerca. Confrontare le due versioni considerando x inserimenti, y ricerche e z cancellazioni su vettori di taglia variabile. Scegliere x,y,z secondo le potenzialità dell'hardware.
● Esercizio 2. Con l'approccio implementativo proposto, scrivere la procedura che realizza la visita in ordine simmetrico dell'albero binario di ricerca
● Esercizio 3. Ripetere l'esercizio 3 della lezione 5 utilizzando un albero binario di ricerca
Università degli Studi di Milano
Marco Frasca
Esercizi
● Esercizio 1.
Università degli Studi di Milano
Marco Frasca
●Come atteso, l'inseri-mento con vettore è più veloce, ma ricerca e can-cellazione sono asintoti-camente più veloci con albero binario
● Per il confronto, atten-zione all'hardware:- se l'hardware è poco performante (poca memoria cache o RAM) i tempi potrebbero essere falsati!
top related