La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Lezione 10 Ordinamento ottimo Ricerca. Sommario Ordinamento Ottimo O(n lg n) Ordinamento O(n) Alberi e Grafi Alberi Binari di Ricerca.

Presentazioni simili


Presentazione sul tema: "Lezione 10 Ordinamento ottimo Ricerca. Sommario Ordinamento Ottimo O(n lg n) Ordinamento O(n) Alberi e Grafi Alberi Binari di Ricerca."— Transcript della presentazione:

1 Lezione 10 Ordinamento ottimo Ricerca

2 Sommario Ordinamento Ottimo O(n lg n) Ordinamento O(n) Alberi e Grafi Alberi Binari di Ricerca

3 Ordinamento Ottimo In un ordinamento per confronto si usa il confronto tra elementi per ottenere informazioni sullordine della sequenza degli elementi dati a e b per determinare lordine relativo fra questi si deve eseguire uno dei seguenti confronti: –a > b –a < b –a b I confronti sono tutti equivalenti, nel senso che forniscono tutti la stessa informazione sullordinamento relativo tra a e b consideriamo pertanto solo a b

4 Albero di decisione Un algoritmo di ordinamento per confronto può essere rappresentato a livello astratto come un albero di decisione un albero di decisione rappresenta i confronti eseguiti da un algoritmo su di una sequenza di ingresso di data dimensione e indica sulle foglie la permutazione dellingresso che corrisponde alla sequenza ordinata dei dati in ingresso

5 Albero di decisione In un albero di decisione non si rappresenta niente altro che i confronti (niente istruzioni per il controllo, copia dati, etc) ogni nodo interno ha etichetta a i :a j con i,j nellintervallo dei dati in ingresso ogni foglia ha una etichetta del tipo [3,5,1,...] con la quale indichiamo una permutazione degli elementi in ingresso (cioè in questo caso consideriamo come risultato prima il terzo elemento, poi il quinto, poi il primo, etc)

6 Albero di decisione Ad ogni nodo interno si compie un confronto: –se a i a j allora si va nel nodo sinistro, altrimenti destro Lesecuzione di un algoritmo consiste nel compiere un cammino nellalbero di decisione a partire dalla radice fino ad una foglia perché si abbia sempre una soluzione si deve garantire che ognuna delle n! permutazioni dellingresso sia rappresentato come una foglia dellalbero di decisione

7 Albero di decisione per Ordinamento a 1 :a 2 a 2 :a 3 a 1 :a 3 [1,2,3] a 1 :a 3 [1,3,2] [3,1,2] [2,1,3] a 2 :a 3 [2,3,1] [3,2,1] Nota: 3 elementi, 3! combinazioni, 6 foglie

8 Limite inferiore Il cammino più lungo in un albero di decisione dalla radice ad una qualunque foglia rappresenta il numero di confronti che lalgoritmo deve eseguire nel caso peggiore questo è pari allaltezza dellalbero un limite inferiore sullaltezza dellalbero di decisione di un algoritmo è dunque un limite inferiore sul tempo di esecuzione di un algoritmo di ordinamento per confronti

9 Teorema sullordinamento ottimo Teorema: –qualunque albero di decisione che ordina n elementi ha altezza (n ln n) Dimostrazione: –Dato che vi sono n! permutazioni di n dati ed ogni permutazione rappresenta un possibile ordinamento allora lalbero binario di decisione deve avere n! foglie –un albero binario di altezza h ha al più 2 h foglie –pertanto: 2 h n! (approssimazione di Stirling) n n –passando ai logaritmi: ln 2 h ln n n –ovvero: h n ln n = (n ln n)

10 Conseguenze Un qualunque algoritmo di ordinamento per confronto non può fare asintoticamente meglio di n ln n Ne consegue che il merge sort e lo heap sort sono algoritmi ottimi in quanto limitati superiormente come O(n ln n)

11 Ordinamento O(n) E tuttavia possibile scrivere algoritmi di ordinamento che operano in tempo O(n)!! Per farlo si deve abbandonare il metodo di ordinamento per confronto Se le chiavi da ordinare sono interi in un intervallo prefissato allora si può utilizzare direttamente il valore della chiave per posizionare lelemento nella giusta posizione nel vettore ordinato finale

12 Counting Sort Il Counting Sort si basa sullipotesi che ognuno degli n elementi in ingresso sia un intero nellintervallo da 1 a k. Se k=O(n) allora il tempo di esecuzione del CountingSort è O(n). Lalgoritmo prende in ingresso un vettore, restituisce un secondo vettore ordinato ed utilizza un vettore di appoggio per lelaborazione

13 Spiegazione Intuitiva di Counting Sort Per ogni elemento x si determinano quanti elementi minori di x vi siano si usa questa informazione per assegnare ad x la sua posizione finale nel vettore ordinato se ad esempio vi sono 8 elementi minori di x allora x andrà messo nella posizione 9 bisogna fare attenzione al caso in cui vi siano elementi coincidenti. In questo caso infatti non vogliamo assegnare a tutti la stessa posizione.

14 Counting Sort CountingSort(A,B,k) 1 for i 1 to k 2 doC[i] 0 3 for j 1 to length[A] 4 do C[A[j]] C[A[j]]+1 5 for i 2 to k 6 do C[i] C[i]+C[i-1] 7 for j length[A] downto 1 8 doB[C[A[j]]] A[j] 9C[A[j]] C[A[j]]-1

15 Visualizzazione A C C B C B C B C B

16 Tempo di calcolo del Counting Sort Esaminando lalgoritmo si osserva che vi sono due cicli di lunghezza k e due di lunghezza n Si può far vedere che la complessità è (k+n) se k= (n) allora la complessità del Counting Sort è complessivamente (n)

17 Stabilità del Counting Sort Lalgoritmo Counting Sort è un metodo di ordinamento stabile infatti elementi con lo stesso valore compaiono nel vettore risultato B nello stesso ordine che avevano nel vettore di ingresso A

18 Radix Sort Il Radix Sort è un algoritmo di ordinamento usato per ordinare record con chiavi multiple Un esempio di record con chiavi multiple è dato dalla data gg/mm/aaaa. Per ordinare per data si deve ordinare lanno e a parità di anno si deve ordinare per mese e a parità di mese per giorno Un altro esempio di record a chiave multipla è dato dal considerare le cifre di un intero come chiavi separate. Per ordinare interi si ordina per la cifra di posizione maggiore e in caso di parità per quelle di ordine via via minore

19 Spiegazione intuitiva Il Radix Sort opera in modo contro intuitivo ordinando prima sulle cifre meno significative e poi su quelle via via più significative Supponiamo di dover ordinare una sequenza di numeri a 3 cifre Utilizzando un ordinamento di tipo stabile possiamo procedere ordinando prima per le unità, poi le decine e in ultimo le centinaia ad ogni passo la stabilità ci garantisce che le cifre precedenti sono già ordinate

20 Esempio Sequenza in ingresso

21 PseudoCodice Radix-Sort(A,d) 1for i 1 to d 2dometodo di ordinamento stabile su cifra i

22 Tempo computazionale Il tempo di esecuzione dipende dallalgoritmo di ordinamento stabile scelto per ordinare le singole cifre se si usa il Counting Sort si ha che per ognuna delle d cifre si impiega un tempo (k+n) pertanto si ha (dk+dn) se d è una costante rispetto a n se k= (n) allora per il radix sort si ha (n)

23 Nota sulle prestazioni Se vogliamo ordinare 10^6 numeri a 3 cifre –con il radix sort si effettua per ogni dato 3 chiamate al counting sort –con algoritmi O(n lg n) per ogni dato si effettuano lg n=20 operazioni Andando a estrarre le costanti numeriche nascoste nella notazione asintotica si vede che il radix sort può essere conveniente Lo svantaggio sta nel fatto che il metodo non è un ordinamento in loco e ha bisogno di più del doppio della memoria dei metodi in loco

24 Definizioni per Grafi e Alberi Di seguito vengono date delle definizioni su grafi ed alberi che saranno utili per comprendere le strutture dati presentate successivamente

25 Grafi Un grafo orientato (o diretto) G è una coppia (V,E) dove V è un insieme finito detto dei vertici e E è una relazione binaria su V che forma linsieme degli archi. Gli archi sono delle coppie ordinate di vertici V={1,2,3,4,5,6} E={(1,2),(2,2),(2,4), (2,5),(4,1),(4,5), (5,4),(6,3)}

26 Grafi Un grafo non orientato è un grafo in cui gli archi sono coppie non ordinate di vertici, cioè un arco fra i vertici u,v è un insieme di due elementi {u,v} piuttosto che una coppia (u,v) tuttavia si indica larco sempre con notazione (u,v)

27 Grafi Sia (u,v) è un arco di un grafo orientato, si dice che: –larco esce dal vertice u –larco entra nel vertice v un arco (u,v) di un un grafo non orientato si dice che è incidente sui vertici v e u si dice che v è adiacente a u –in un grafo non orientato la relazione di adiacenza è simmetrica –in un grafo orientato v è adiacente a u, ma non è vero il viceversa, e si indica con la notazione u v

28 Grafi Il grado di un vertice in un grafo non orientato è il numero di archi incidenti sul vertice in un grafo orientato il grado uscente (entrante) di un vertice è il numero di archi uscenti (entranti) dal vertice

29 Grafi Un cammino di lunghezza k da un vertice a ad un vertice b in un grafo G=(V,E) è una sequenza di vertici tali che –a= v 0 –b= v k –(v i-1,v i ) E per i=1,…,k La lunghezza di un cammino è il suo numero di archi un cammino è un ciclo se v 0 = v k un grafo senza cicli si dice aciclico un grafo non orientato è connesso se ogni coppia di vertici è collegata con un cammino

30 Alberi Un albero è un grafo non orientato, connesso e aciclico. Un albero radicato è un albero in cui si distingue un vertice (chiamato radice) dagli altri vertici i vertici in un albero sono chiamati nodi sia x un nodo di un albero con radice r: qualunque nodo y sullunico cammino da r a x è chiamato antenato di x e x si dice discendente di y il sottoalbero radicato in x è lalbero indotto dai discendenti di x, radicato in x

31 Alberi Se lultimo arco di un cammino dalla radice r ad un nodo x è larco (y,x) allora y è il padre di x e x è il figlio di y la radice è lunico nodo che non ha padre due nodi con lo stesso padre si dicono fratelli un nodo senza figli si dice nodo esterno o foglia un nodo non foglia è un nodo interno il numero di figli di un nodo x è il grado di x

32 Alberi la lunghezza di un cammino da r a x è la profondità di x la profondità massima di un qualunque nodo di un albero è laltezza dellalbero un albero ordinato è un albero radicato in cui i figli di ciascun nodo sono ordinati (cioè si distingue il primo figlio, il secondo, etc)

33 Alberi binari Un albero binario è una struttura definita su un insieme finito di nodi che: –non contiene nessun nodo, oppure –è composto da tre insiemi disgiunti di nodi: un nodo radice, un albero binario chiamato sottoalbero sinistro e un albero binario chiamato sottoalbero destro un albero binario che non contiene nessun nodo è detto albero vuoto o albero nullo (denotato con NIL) se il sottoalbero sinistro (destro) non è vuoto allora la sua radice è detta figlio sinistro (destro) se un sottoalbero è lalbero nullo si dice che il figlio è assente o mancante

34 Alberi binari Un albero binario non è un albero ordinato con nodi con grado al più due: in un albero ordinato non si distingue fra figlio destro o sinistro (ma si considera solo il numero di figli)

35 Alberi in generale si parla di alberi posizionali per quegli alberi in cui i figli dei nodi sono etichettati con interi positivi distinti li-esimo figlio di un nodo è assente se nessun figlio è etichettato con lintero i Un albero k-ario è un albero posizionale in cui per ogni nodo tutti i figli con etichetta più grande di k sono assenti

36 Alberi Un albero k-ario completo è un albero k-ario in cui tutte le foglie hanno la stessa profondità e tutti i nodi interni hanno grado k Il numero di foglie di un albero k-ario è: –la radice ha k figli a profondità 1 –ognuno dei figli ha k figli a profondità 2 per un totale di k.k foglie –a profondità h si hanno k h foglie il numero di nodi interni di un albero k-ario completo di altezza h è: 1+k+ k 2 + … +k h-1 = i=0..h-1 k i = (k h -1)/(k-1) quindi un albero binario ha 2 h -1 nodi interni

37 Implementazione alberi binari Gli alberi si rappresentano ricorrendo agli stessi metodi usati per rappresentare le liste In genere si usano strutture dati con puntatori Per gli alberi binari si usano strutture dati per rappresentare i nodi che hanno un campo key e 2 o 3 puntatori ad altri nodi (si può non utilizzare il puntatore a padre) struct Node{ int key; Node* p; Node * left, * right; };

38 Implementazione alberi binari Se x è un nodo allora –se p[x]=NIL il nodo è la radice dellalbero –se left[x]=NIL (right[x]=NIL) allora il nodo non ha figlio sinistro (destro) Si mantiene il puntatore alla radice dellalbero T memorizzandola nellattributo root[T] –se root[T]=NIL lalbero è vuoto

39 Visualizzazione alberi binari key p left right Ø ØØ ØØØØ

40 Implementazione alberi Se vogliamo rappresentare alberi con un numero illimitato di figli potremmo pensare di riservare un numero max di link ai figli come: ma in questo modo dobbiamo porre un limite sul massimo grado di un nodo inoltre viene sprecato molta memoria per rappresentare i puntatori NIL key p 1st 2nd 3rd 4th... Ø2

41 Implementazione alberi Per rappresentare alberi con un numero illimitato di figli conviene usare la rappresentazione figlio-sinistro fratello-destro Ogni nodo conserva il campo key e puntatore a padre invece di avere un puntatore per ogni figlio i nodi hanno solo due puntatori: –puntatore al figlio più a sinistra –puntatore al fratello immediatamente a destra

42 Visualizzazione

43

44 Algoritmi su gli alberi binari: visite Dato un puntatore alla radice di un albero vogliamo scandire in modo sistematico tutti i nodi di tale albero In una lista abbiamo una unica possibilità: quella di seguire il link al nodo successivo Con un albero binario sono possibili 3 strategie: –preordine o ordine anticipato: si visita prima il nodo e poi i sottoalberi sinistro e destro –inordine o ordine simmetrico: si visita prima il sottoalbero sinistro e poi il nodo e poi il sottoalbero destro –postordine o ordine posticipato: si visita prima il sottoalbero sinistro, poi quello destro e poi il nodo

45 Visita in ordine simmetrico Inorder-Tree-Walk(x) 1if x NIL 2thenInorder-Tree-Walk(left[x]) 3stampa(key[x]) 4Inorder-Tree-Walk(right[x])

46 Visualizzazione si parte in 2 viene chiamata la funzione sul figlio sinistro siamo in 1 viene chiamata la funzione sul figlio sinistro non esiste figlio sinistro e la ricorsione termina torniamo in 1 stampiamo 1 viene chiamata la funzione sul figlio destro non esiste figlio destro e la ricorsione termina torniamo in 1 la funzione termina torniamo in 2 stampiamo 2 ….

47 Visualizzazione viene chiamata la funzione sul figlio destro siamo in 8 viene chiamata la funzione sul figlio sinistro siamo in 4 viene chiamata la funzione sul figlio sinistro non esiste figlio sinistro e la ricorsione termina torniamo in 4 stampiamo 4 viene chiamata la funzione sul figlio destro non esiste figlio destro e la ricorsione termina la funzione termina torniamo in 8 stampiamo 8 viene chiamata la funzione sul figlio destro siamo in 9

48 Visualizzazione viene chiamata la funzione sul figlio sinistro non esiste figlio sinistro e la ricorsione termina torniamo in 9 stampiamo 9 viene chiamata la funzione sul figlio destro non esiste figlio destro e la ricorsione termina torniamo in 9 la funzione termina torniamo in 8 la funzione termina torniamo in 2 la funzione termina

49 Visita in ordine anticipato Inorder-Tree-Walk(x) 1if x NIL 2thenstampa(key[x]) 3Inorder-Tree-Walk(left[x]) 4Inorder-Tree-Walk(right[x])

50 Visualizzazione si parte in 2 stampiamo 2 viene chiamata la funzione sul figlio sinistro siamo in 1 stampiamo 1 viene chiamata la funzione sul figlio sinistro non esiste figlio sinistro e la ricorsione termina torniamo in 1 viene chiamata la funzione sul figlio destro non esiste figlio destro e la ricorsione termina torniamo in 1 la funzione termina torniamo in 2

51 Visualizzazione viene chiamata la funzione sul figlio destro siamo in 8 stampiamo 8 viene chiamata la funzione sul figlio sinistro siamo in 4 stampiamo 4 viene chiamata la funzione sul figlio sinistro non esiste figlio sinistro e la ricorsione termina torniamo in 4 viene chiamata la funzione sul figlio destro non esiste figlio destro e la ricorsione termina la funzione termina torniamo in 8 viene chiamata la funzione sul figlio destro siamo in 9

52 Visualizzazione viene chiamata la funzione sul figlio sinistro non esiste figlio sinistro e la ricorsione termina torniamo in 9 viene chiamata la funzione sul figlio destro non esiste figlio destro e la ricorsione termina torniamo in 9 la funzione termina torniamo in 8 la funzione termina torniamo in 2 la funzione termina

53 Visita in ordine posticipato Inorder-Tree-Walk(x) 1if x NIL 2thenInorder-Tree-Walk(left[x]) 3Inorder-Tree-Walk(right[x]) 4stampa(key[x])

54 Algoritmi ricorsivi su alberi binari Capita di dover determinare dei parametri strutturali di un albero avendo in ingresso solo il link alla radice Si può sfruttare la struttura ricorsiva degli alberi ed realizzare versioni ricorsive delle funzioni di interesse Consideriamo una funzione per determinare il numero di nodi ed una per determinare laltezza dellalbero

55 Funzioni ricorsive int count(link h) { if (h == NULL) return 0; return count(h->l) + count(h->r) + 1; } int height(link h) { int u, v; if (h == NULL) return -1; u = height(h->l); v = height(h->r); if (u > v) return u+1; else return v+1; }

56 Ricerca Molte applicazioni richiedono un insieme dinamico che fornisca solo operazioni di inserimento/cancellazione e ricerca o al più la ricerca di elementi particolari della collezione come il massimo/minimo o il predecessore/successore

57 Alberi Binari di ricerca Gli alberi binari di ricerca sono strutture dati dinamiche che forniscono le operazioni richieste (insert, delete, search, maximum, predecessor, etc) in tempo limitato asintoticamente dallaltezza dellalbero, cioè per le varie operazioni si ha T(n)=O(h) Quando gli alberi sono bilanciati questo comporta avere tempi di calcolo asintotici O(ln n) Tuttavia si possono avere alberi sbilanciati. Un albero può degenerare in un lista lineare. In questo caso si hanno tempi O(n)

58 Alberi Binari di Ricerca Un albero binario di ricerca è un albero binario in cui le chiavi soddisfano la proprietà dellalbero binario di ricerca: –sia x un nodo –key di left[x] key di x –key di right[x] key di x

59 Ordinamento delle chiavi In un albero binario di ricerca loperazione di ordinamento viene eseguita semplicemente attraversando i nodi dellalbero in modo ricorsivo la visita deve essere una visita in ordine simmetrico

60 Visualizzazione Root[t] Sequenza stampata:

61 La ricerca Lidea è di confrontare la chiave di un nodo x con la chiave cercata nel caso che non coincidano si cerca solo nel sottoalbero in cui potrà trovarsi è possibile sapere quale sia il sottoalbero perché tutti i nodi del sottoalbero destro contengono chiavi maggiori della chiave di x (e nel sottoalbero sinistro chiavi minori)

62 PseudoCodice per la Ricerca (versione ricorsiva) Tree-Search(x,k) 1if x = NIL o k=key[x] 2thenreturn x 3if k < key[x] 4thenreturn Tree-Search(left[x],key) 5else return Tree-Search(right[x],key)

63 Tempo di calcolo La procedura discende a partire dalla radice lalbero e restituisce un puntatore al nodo la cui chiave coincide con la chiave cercata nel caso in cui essa non esista la procedura discende comunque fino ad una foglia e restituisce un puntatore nullo Il tempo impiegato è proporzionale alla lunghezza del cammino percorso, ovvero limitato dalla altezza dellalbero pertanto T(n)=O(h)

64 Nota E possibile scrivere qualsiasi procedura ricorsiva in forma non ricorsiva (e viceversa) La forma ricorsiva è spesso più elegante e compatta ma non la più efficiente Di seguito si da una procedura non ricorsiva per la ricerca in un albero binario

65 PseudoCodice per la Ricerca (versione iterativa) Iterative-Tree-Search(x,k) 1while x NIL e k key[x] 2doif k < key[x] 4thenx left[x] 5 else x right[x] 6return x

66 Determinazione della chiave massima e minima La chiave massima in un albero binario dovrà trovarsi nel sottoalbero destro della radice e nel sottoalbero destro del figlio destro della radice e così via Analogamente per la chiave minima che dovrà essere nel sottoalbero sinistro Pertanto per determinare lelemento massimo è sufficiente discendere tutti i nodi da figlio destro in figlio destro fino ad arrivare alla foglia (e analogamente con i figli sinistri per il minimo)

67 Minimo e massimo Tree-Minimum(x) 1while left[x] NIL 2do x left[x] 3return x Tree-Maximum(x) 1while right[x] NIL 2do x right[x] 3return x

68 Successore e predecessore Dato un nodo nellalbero di ricerca talvolta si richiede di determinare il suo successore (o predecessore) secondo lordinamento fornito dalle chiavi. Se tutte le chiavi sono distinte, il successore di un nodo x è il nodo con la più piccola chiave maggiore della chiave di x Con gli alberi binari di ricerca è possibile determinare il successore (predecessore) di un nodo senza dover confrontare le chiavi

69 Idea intuitiva Si considerano due casi: –il nodo x ha un figlio destro –il nodo x non ha un figlio destro Nel primo caso si considera il sottoalbero destro che contiene sicuramente nodi con chiavi maggiori della chiave di x in questo sottoalbero il nodo con la chiave più piccola è la foglia alla estrema sinistra, cioè il nodo restituito dalla procedura Tree-Minimum

70 Idea intuitiva Nel caso in cui x non ha un figlio destro allora il predecessore deve essere un antenato p di x per p, x deve essere un discendente appartenente ad un sottoalbero sinistro (così la chiave di p è maggiore della chiave di x) perché la chiave di p sia la più piccola possibile allora p deve essere lantenato più prossimo –altrimenti se consideriamo il nonno di x, padre di p, è vero che questo ha chiave > chiave[x] ma non è la minima, perché anche chiave[p]>chiave[x] ma chiave[p]

71 Idea intuitiva Per determinare questo nodo antenato è sufficiente risalire gli antenati di x fino a quando non si trova un nodo che è un figlio sinistro di qualche altro nodo y. Il nodo y sarà il nodo cercato si mantengono pertanto i puntatori x e y ai nodi figlio e padre e si risale fino a quando x=left[y]

72 Visualizzazione Successore di 13

73 PseudoCodice Successore Tree-Successore(x) 1if right[x] NIL 2thenreturn Tree-Minimum(right[x]) 3y p[x] 4while y NIL e x = right[y] 5dox y 6y p[x] 7return y

74 Predecessore La procedura per la determinazione del predecessore è simmetrica a quella vista per il successore il predecessore si troverà nel sottoalbero sinistro (se questo esiste), e sarà lelemento massimo di questo sottoalbero se non esiste sottoalbero sinistro il predecessore sarà lantenato più prossimo che ha un figlio destro che è antenato del nodo in questione

75 PseudoCodice Predecessore Tree-Predecessore(x) 1if left[x] NIL 2thenreturn Tree-Maximum(left[x]) 3y p[x] 4while y NIL e x = left[y] 5dox y 6y p[x] 7return y

76 Inserzione Per inserire un nuovo valore k in un albero binario di ricerca: – si passa alla procedura un nodo z tale che key[z]=k, e left[z]=right[z]=p[k]=NIL –si modificano i campi del nuovo nodo per inserirlo opportunamente allinterno dellalbero binario di ricerca lidea è di muoversi allinterno dellalbero a partire dalla radice spostandosi sul sottoalbero destro o sinistro come appropriato (confrontando le chiavi) una volta arrivati ad una foglia si inserisce il nuovo nodo

77 Visualizzazione

78 Pseudocodice Inserzione Tree-Insert(T,z) 1y NIL 2x root[T] 3while x NIL 4do y x 5if key[z]

79 Cancellazione La procedura di cancellazione è più laboriosa in quanto si deve tenere conto di tre casi possibili dato un nodo z i casi sono: –z non ha figli –z ha un unico figlio –z ha due figli Nel primo caso si elimina direttamente il nodo z il secondo caso è identico al caso di eliminazione di un nodo da una lista concatenata Nel terzo caso si determina il successore di z e lo si sostituisce a z

80 Visualizzazione caso

81 Visualizzazione caso

82 Visualizzazione caso

83 PseudoCodice Cancellazione Tree-Delete(T,z) 1if left[z]=NIL o right[z]=NIL //identifica il nodo da cancellare o sostituire 2theny z 3elsey Tree-Successor(z) 4if left[y] NIL 5then x left[y] 6elsex right[y] 7if x NIL //ripristina il padre (cancellazione implicita) 8then p[x] p[y] 9if p[y] = NIL //ripristina i figli corretti 10thenroot[T] x 11elseif y=left[p[y]] 12thenleft[p[y]] x 13elseright[p[y]] x 14if y z 15thenkey[z] key[y] 17return y //per eventuale deallocazione

84 Implementazione C++ #include using namespace std; template class TreeClass{ private: struct Node{Node *left, *right, * parent; T key;}; Node *root; public: TreeClass():root(0){} void insert(T); void print(){p_print(root); cout<

85 Implementazione C++ template void TreeClass ::p_print(Node *x){ if(x!=0){ p_print(x->left); cout key<<" "; p_print(x->right); } template bool TreeClass ::p_search(Node * x, T usr_key){ LessClass less; if(x==0) return false; if(!less(x->key,usr_key) && !less(usr_key,x->key)) return true; //ugualianza if(less(usr_key,x->key)) p_search(x->left, usr_key); else p_search(x->right, usr_key); }

86 template void TreeClass ::insert(T usr_key){ LessClass less; //inizializzazione del nodo da aggingere Node * z=new Node; z->key=usr_key; z->left=0; z->right=0; z->parent=0; //ricerca della giusta posizione di inserzione Node * y=0; Node * x=root; while(x != 0){ y=x; if(less(z->key, x->key)) x=x->left; else x=x->right; } //settaggio dei puntatori z->parent=y; if(y==0) root=z; else if(less(z->key, y->key)) y->left=z; else y->right=z; }

87 template T TreeClass ::minimum(){ Node * x=root; while(x->left !=0) x=x->left; return x->key; } template T TreeClass ::maximum(){ Node * x=root; while(x->right !=0) x=x->right; return x->key; } Implementazione C++

88 template struct LessClass{ bool operator()(const T & a, const T & b)const{return a T; for(int i=0;i<10;i++) T.insert(v[i]); T.print(); cout<<"Seraching 5:"<< (T.search(5)? "Found":"Not found")<

89 Implementazione C++ //char example char c[]="this_is_a."; TreeClass > Tc; for(int i=0;i<10;i++) Tc.insert(c[i]); Tc.print(); cout<<"Seraching s:"<< (Tc.search('s')? "Found":"Not found")<


Scaricare ppt "Lezione 10 Ordinamento ottimo Ricerca. Sommario Ordinamento Ottimo O(n lg n) Ordinamento O(n) Alberi e Grafi Alberi Binari di Ricerca."

Presentazioni simili


Annunci Google