Fondamenti di Informatica Prof. E. Clementini. Dispensa didattica A.A
|
|
- Tiziano Quaranta
- 8 anni fa
- Visualizzazioni
Transcript
1 Argomenti: Fondamenti di Informatica Prof. E. Clementini Dispensa didattica A.A Efficienza dei programmi. La funzione t(n). Modello di costo. Calcolo della t(n) per programmi iterativi. Caso migliore, caso peggiore, e caso medio. Complessità computazionale. Notazione asintotica O ( g( n)), ( g ( n)), ( g ( n)). Delimitazioni alla complessità di un problema. Calcolo della t(n) per programmi ricorsivi. Soluzione dell equazione di ricorrenza per il fattoriale e per i numeri di Fibonacci. 2. Algoritmi di ricerca e ordinamento. Ricerca sequenziale. Ricerca binaria. Inserimento e cancellazione in un array ordinato. SelectionSort. InsertionSort. Bubblesort. Mergesort. Quicksort: analisi della complessità nel caso migliore e nel caso peggiore. 3. Tipi di dato astratti. Liste: definizioni, rappresentazione con array, rappresentazione con lista collegata, rappresentazione con lista collegata bidirezionale, operazioni primitive sulle liste. Pile: definizioni, rappresentazione con array, rappresentazione con lista collegata, operazioni primitive sulle pile. Code: definizioni, prima rappresentazione con array, seconda rappresentazione con array (gestione circolare), rappresentazione con lista collegata, operazioni primitive sulle code. Alberi: definizioni, alberi n-ari, alberi binari, algoritmi di visita in profondità e in larghezza. Alberi binari: rappresentazione con puntatori, codifica delle operazioni primitive. Calcolo della complessità in programmi che fanno uso di tipi astratti. Università degli Studi dell Aquila 1
2 1. Efficienza dei programmi Calcolo della t(n) Calcolo della t(n) per un ciclo for Numeriamo le istruzioni elementari rispettando lo stesso ordine di esecuzione del diagramma di flusso. Quindi nell esempio seguente l incremento della variabile è numerato dopo le istruzioni interne al ciclo: 1 2 for(i=0;i<n;i++) cin>>x; 3 somma=somma+x; 5 4 Tabella costo/frequenza: # istr. costo freq n n 4 1 n 5 1 n t(n)=4n+2 Calcolo della t(n) per un doppio ciclo. Due casi: a) il numero di esecuzioni del ciclo interno non dipende dall iterazione del ciclo esterno; b) il numero di esecuzioni del ciclo interno dipende dall iterazione del ciclo esterno. Caso a) somma dei valori di una tavola pitagorica: 1 2 for (i=1;i<=n;i++) for (j=1;j<=n;j++) somma=somma+ i*j; 5 7 Università degli Studi dell Aquila 2
3 # istr. costo freq n n 4 1 n(n+1) n n 7 1 n t(n)=3 n 2 +4n+2 Caso b) Piramide di numeri: 1 2 for (i=1;i<=n;i++) 5 3 for (j=1;j<=i;j++) cout<<j; Il costo del ciclo interno può essere calcolato determinando la sua frequenza per ogni valore del contatore esterno i: per i=1: 1 j 1, freq. 1 per i=2: 1 j 2, freq. 2 per i=n: 1 j n, freq. n Il totale delle frequenze parziali è Tabella: n k 1 k = n(n 2 1). # istr. costo freq n n 4 1 n(n+1)/2+n 5 1 n(n+1)/2 6 1 n(n+1)/2 7 1 n 3 11 t(n)= n 2 n Università degli Studi dell Aquila 3
4 Complessità computazionale Notazione asintotica Limite asintotico superiore O ( g( n)) O ( g( n)) = f ( n) c, n,0 f ( n) cg( n), n 0 n0 Limite asintotico inferiore ( g ( n)) ( g ( n)) = f ( n) c, n,0 cg( n) f ( n), n 0 n0 Limite asintotico stretto ( g ( n)) ( g ( n)) = f ( n) c, c, n,0 c g( n) f ( n) c g( n), n n0 Proprietà della notazione asintotica: - fattore costante: k, f (n), k f ( n) ( f ( n)) - transitività: f ( n) ( g( n)), g ( n) ( h( n)) f ( n) ( h( n)) - somma: f ( n) g( n) = (max f ( n), g( n)) - prodotto: f n) ( g ( )), f n) ( g ( )) f n) f ( ) = g ( n) g ( )) 1( 1 n 2 ( 2 n 1( 2 n ( 1 2 n Istruzione dominante L istruzione dominante è l istruzione che viene ripetuta con frequenza maggiore in un programma. Se riusciamo a calcolare la frequenza e quindi la complessità dell istruzione dominante, conosciamo la complessità di tutto l algoritmo. Delimitazione superiore di un problema Un problema ha una delimitazione superiore O ( f ( n)) se esiste almeno un algoritmo che lo risolve con complessità O ( f ( n)). Delimitazione inferiore di un problema Un problema ha una delimitazione inferiore ( f ( n)) se ogni algoritmo che lo risolve ha complessità almeno ( f ( n)). Soluzione ottima di un problema Dato un problema con una delimitazione inferiore ( f ( n)), una soluzione ottima è un algoritmo che risolve il problema con complessità ( f ( n)). Università degli Studi dell Aquila 4
5 Calcolo t(n) di una funzione ricorsiva Funzione fattoriale int fatt (int n) 1 2 if (n==0) return 1; return n*fatt(n-1); 3 # istr. costo freq. (n>0) freq. (n=0) t(n-1) 1 0 Equazione di ricorrenza: t(n)=t(n-1)+1 per n>0 e t(0)=2 Risolviamo per sostituzione: t(n-1)=t(n-2)+1 t(n)=t(n-2)+2 t(n-2)=t(n-3)+1 t(n)=t(n-3)+3 t(n)=t(0) +n t(n)=n+2 Numeri di Fibonacci Un termine della serie di Fibonacci è definito matematicamente come: f ; 0 1 f ; 1 1 f f f, n 1. n n 1 n 2 Università degli Studi dell Aquila 5
6 Soluzione ricorsiva: int fib(int n) 1 if (n==0 n==1) return 1; return fib(n-1)+fib(n-2); 2 3 # istr. costo freq. (n>1) freq. (n=0 or n=1) t(n-1)+t(n-2) 1 0 Equazione di ricorrenza: t(n)=t(n-1)+t(n-2)+1 per n>1 e t(n)=2 per n=0 or n=1 per sostituzione: t(n-1)=t(n-2)+t(n-3)+1 t(n)= t(n-2)+t(n-3)+1 +t(n-2) +1 = 2 t(n-2) +t(n-3) +2 t(n-2)=t(n-3)+t(n-4)+1 t(n)=2 t(n-3) +2 t(n-4) +2 +t(n-3) +2 = 3 t(n-3)+2t(n-4)+4 t(n-3)=t(n-4)+t(n-5)+1 t(n)=3t(n-4)+3t(n-5)+3+2t(n-4)+4 = 5t(n-4)+3t(n-5) +7 t(n-4)=t(n-5)+t(n-6)+1 t(n)=5t(n-5)+5t(n-6)+5+3t(n-5) +7 = 8t(n-5)+5t(n-6)+12 = f 5 t(n-5)+ f 4 t(n-6)+ f 6-1 t(n)= f 6 t(n-6) + f 5 t(n-7) + f t(n)= f n 1t(1) + f n 2 t(0) + f n -1 = 2 f n 1+2 f n 2 t(n)= 3 f n 1 + n f -1 = 2( f n 1 + f n 2 )+ f n -1 = 3 f n -1. La funzione t(n) cresce come i numeri di Fibonacci, quindi è esponenziale. Infatti, si trova empiricamente che una delimitazione per i numeri di Fibonacci è la seguente: f n n L algoritmo iterativo per calcolare i numeri di Fibonacci ha invece costo lineare. Università degli Studi dell Aquila 6
7 2. Algoritmi di ricerca e ordinamento Ricerca sequenziale L ordinamento dei valori contenuti in un array, in senso crescente o decrescente, è utile per ritrovare più facilmente i valori in svariate applicazioni. Sono i tempi di calcolo ad essere inferiori se dobbiamo ritrovare un valore all interno di un array ordinato piuttosto che all interno di un array non ordinato. Il problema della ricerca può essere formulato come segue: Esiste il valore k all interno dell array v?. Per rispondere, in un array non ordinato possiamo solo adottare un cosiddetto algoritmo di ricerca sequenziale, costituito da un ciclo che scandisce tutto l array. Osserviamo il seguente frammento di codice: i=0; 1 trovato=false; 2 while(i<n &&!trovato) if (v[i]==k) 4 trovato=true; i++; 6 Come si può vedere, il tempo di esecuzione è più o meno sfavorevole a seconda della posizione che l elemento cercato assume all interno dell array. Se l elemento non dovesse essere presente, abbiamo dovuto esaminare tutto l array per giungere a questa conclusione. Il caso peggiore corrisponde a trovare l elemento in ultima posizione (oppure in modo quasi equivalente a non trovarlo affatto), mentre il caso migliore corrisponde a trovare l elemento in prima posizione. Il caso medio può essere calcolato con considerazioni statistiche: se ipotizziamo che il numero di elementi dell array n sia uguale al numero di valori possibili, è lecito ipotizzare che mediamente il valore k si trova a metà array. # istr. costo freq. (c.p.) freq. (c.migliore) freq. (c.medio) n+1 2 n/ n 1 n/ n 1 n/2 Caso peggiore t(n)=3n+4 Caso migliore t(n)=7 Caso medio t(n)=3n/ Università degli Studi dell Aquila 7
8 Applicando lo stesso algoritmo ad un array ordinato in senso crescente, possiamo migliorare il codice aggiungendo un ulteriore condizione di uscita quando il valore contenuto nell array supera il valore da cercare: i=0; trovato=false; while(i<n &&!trovato && v[i]<=k) if (v[i]==k) trovato=true; i++; In questa versione il caso peggiore si verifica quando l elemento cercato è in ultima posizione oppure quando è più grande di tutti i valori dell array. Il caso migliore si verifica quando l elemento cercato è più piccolo di tutti i valori dell array (in questo caso non si entra per niente nel ciclo): # istr. costo freq. (c.p.) freq. (c.m.) n n n 0 Caso peggiore t(n)=3n+4 Caso migliore t(n)=3 Ricerca binaria In un array ordinato, è possibile applicare un algoritmo molto più efficiente, la cosiddetta ricerca binaria. In questo algoritmo, si accede all elemento di mezzo dell array v[med] e si controlla se esso è maggiore o minore del valore cercato k: se è maggiore, il valore k dovrà trovarsi nella prima metà dell array, altrimenti nella seconda metà. Pertanto dopo un solo controllo l algoritmo ha escluso metà degli elementi. Ripetendo il procedimento sulla metà interessata, si potrà escludere un altro quarto di array, e così via. Si intuisce che dopo pochi controlli, si arriva subito alla conclusione. Consideriamo il seguente esempio: v min med max Università degli Studi dell Aquila 8
9 Il valore di med in questo caso è uguale a 5. Supponiamo che k sia uguale a 10. Poiché v[5] è maggiore di 10, si assegna a max il valore di med-1. Nell iterazione successiva, in questo modo si considera la prima metà dell array per cercare il valore k. La codifica in C++ è la seguente: max=n-1; 1 min=0; 2 trovato=false; 3 4 while(max>=min &&!trovato) med=(max+min)/2; 5 if (v[med]==k) 6 trovato=true; 7 8 if (v[med]>k) max=med-1; 9 min=med+1; Il caso peggiore corrisponde all elemento non presente nell array e il caso migliore all elemento trovato durante la prima iterazione: # istr. costo freq. (c.p.) freq. (c.m.) log 2 n log 2 n log 2 n log 2 n log 2 n Caso peggiore t(n)=5 Caso migliore t(n)=8 log n +9 2 Il costo logaritmico è dovuto al numero di divisioni necessarie partendo da un vettore di n elementi per arrivare a una parte di vettore costituita da un solo elemento. Università degli Studi dell Aquila 9
10 Inserimento e cancellazione in un array ordinato Quando si ha a disposizione un array ordinato, è conveniente mantenerlo ordinato anche in seguito all aggiunta o alla cancellazione di nuovi valori. Partiamo ad esempio dall array seguente e supponiamo di voler inserire un nuovo valore x=20: per mantenere l ordinamento, dobbiamo memorizzare x in posizione p=4 e spostare tutti gli altri valori in avanti di una posizione: v Il frammento di codice seguente esegue l inserimento di un valore x in un array ordinato in posizione p: for (int i=n-1;i>=p;i--) v[i+1]=v[i]; 3 v[p]=x; 5 n++; Il risultato sarà il seguente: 4 v Ovviamente per poter spostare i valori in avanti, l array deve essere stato dichiarato con un numero di elementi maggiore di n. Il caso peggiore corrisponde all inserimento per p=0, quando bisognerà spostare tutti gli elementi presenti in avanti, e il caso migliore all inserimento per p=n, quando sarà sufficiente memorizzare il valore nella prima posizione libera del vettore senza dover spostare elementi: # istr. costo freq. (c.p.) freq. (c.m.) n n n Caso peggiore t(n)=3n+4 Caso migliore t(n)=4 Università degli Studi dell Aquila 10
11 In maniera equivalente, per la cancellazione di un valore in posizione p, si dovranno spostare all indietro tutti i valori successivi alla posizione stessa. Si osservi il frammento di codice: for (int i=p;i<n-1;i++) v[i]=v[i+1]; 3 n--; 4 Il caso peggiore corrisponde alla cancellazione per p=0, quando bisognerà spostare i restanti n-1 elementi del vettore all indietro, e il caso migliore all inserimento per p=n-1, quando sarà sufficiente diminuire di 1 il numero n senza dover spostare elementi: # istr. costo freq. (c.p.) freq. (c.m.) n n n Caso peggiore t(n)=3n Caso migliore t(n)=3 Università degli Studi dell Aquila 11
12 Selectionsort Per poter usare la ricerca binaria, è necessario ordinare i valori di un array nel caso si parta da valori disordinati. Esistono svariati algoritmi di ordinamento, che si differenziano in base alle prestazioni. In questa sezione, vediamo un semplice algoritmo, chiamato ordinamento per selezione, che non è tra i più efficienti. L ordinamento per selezione si basa sul trovare il valore più piccolo dell array e scambiare tale valore con quello in prima posizione. Successivamente, si trova il valore più piccolo tra gli n-1 valori rimasti e si mette in seconda posizione, e così via. Il frammento di codice relativo è il seguente: 1 2 for (i=0;i<n-1;i++) min=i; for (j=i+1;j<n;j++) if (v[j]<v[min]) min=j; temp=v[i]; 9 v[i]=v[min]; 10 v[min]=temp; Il caso peggiore corrisponde ad un array ordinato in senso inverso, mentre il caso migliore ad un array già ordinato. Tuttavia, come si vede nella tabella costi-frequenze, i due casi praticamente coincidono a meno del costo dell istruzione n. 7. Il costo del ciclo interno può essere calcolato determinando la sua frequenza per ogni valore del contatore esterno i: per i=0: 1 j n 1, freq. n-1 per i=1: 2 j n 1, freq. n-2 per i=n-2: n 1 j n 1, freq. 1 Il totale delle frequenze parziali è n 1 k 1 k = n(n 2 1). Università degli Studi dell Aquila 12
13 Tabella: # istr. costo freq. (c.p.) freq. (c.m.) n n 3 1 n-1 n n-1 n n(n-1)/2+n-1 n(n-1)/2+n n(n-1)/2 n(n-1)/2 7 1 n(n-1)/ n(n-1)/2 n(n-1)/2 9 1 n-1 n n-1 n n-1 n n-1 n-1 Caso peggiore t(n)= 2n 2 6n Caso migliore t(n)= n 2 n Università degli Studi dell Aquila 13
14 Insertionsort L algoritmo di ordinamento per inserimento, o insertionsort, si basa sull inserire man mano dei valori all interno di una parte di array già ordinata. Il frammento di codice relativo è il seguente: 1 2 for (i=0;i<n-1;i++) x=v[i+1]; for (j=i;j>=0 && v[j]>x;j--) v[j+1]=v[j]; 6 7 v[j+1]=x; 8 Il caso peggiore corrisponde ad un array ordinato in senso inverso, mentre il caso migliore ad un array già ordinato. Nel caso migliore l algoritmo diventa lineare. Il costo del ciclo interno può essere calcolato determinando la sua frequenza per ogni valore del contatore esterno i: per i=0: 0 j 0, freq. 1 per i=1: 1 j 0, freq. 2 per i=n-2: n 2 j 0, freq. n-1 Il totale delle frequenze parziali è n 1 k 1 k = n(n 2 1). # istr. costo freq. (c.p.) freq. (c.m.) n n 3 1 n-1 n n-1 n n(n-1)/2+n-1 n n(n-1)/ n(n-1)/ n-1 n n-1 n Caso peggiore t(n)= n 2 n Caso migliore t(n)= 6n 4 Università degli Studi dell Aquila 14
15 Bubblesort L algoritmo di ordinamento a bolle, o bubblesort, si basa sull effettuare confronti tra elementi adiacenti, che vanno scambiati se non rispettano l ordinamento. Il procedimento va ripetuto fino all ordinamento completo del vettore. Ad ogni iterazione interna, l algoritmo assicura che l elemento più piccolo della parte ancora da ordinare affiora fino ad accodarsi alla parte già ordinata. Questo schema base può essere migliorato osservando che se un iterazione interna non effettua nessuno scambio di elementi, allora il vettore risulta essere ordinato e quindi si può interrompere il procedimento. Il frammento di codice relativo è il seguente: i=0; do 1 scambio=false; for (j=n-1;j>i;j--) if (v[j]<v[j-1]) 5 temp=v[j]; 6 v[j]=v[j-1]; 7 v[j-1]=temp; scambio=true; 8 9 i=i+1; while(i<n-1 && scambio); Il caso peggiore corrisponde ad un array ordinato in senso inverso, mentre il caso migliore ad un array già ordinato. Nel caso migliore l algoritmo diventa lineare. Il costo del ciclo interno può essere calcolato determinando la sua frequenza per ogni valore del contatore esterno i: per i=0: n 1 j 1, freq. n-1 per i=1: n 1 j 2, freq. n-2 per i=n-2: n 1 j n 1, freq. 1 Il totale delle frequenze parziali è n 1 k 1 k = n(n 2 1). Università degli Studi dell Aquila 15
16 # istr. costo freq. (c.p.) freq. (c.m.) n n n(n-1)/2+n-1 n 5 1 n(n-1)/2 n n(n-1)/ n(n-1)/ n(n-1)/ n(n-1)/ n(n-1)/2 n n n Caso peggiore t(n)= n 2 n Caso migliore t(n)= 3n 3 Tabella comparativa dei tre metodi quadratici di ordinamento: Algoritmo Caso peggiore Caso migliore Selectionsort 2n 2 6n n 2 n Insertionsort n 4 n n Bubblesort n 3 n n Università degli Studi dell Aquila 16
17 Mergesort L algoritmo di ordinamento per fusione (mergesort) segue l approccio divide et impera : si divide il problema in sottoproblemi; si risolvono i sottoproblemi; si combinano i risultati. In particolare, in questo algoritmo si divide il vettore per 2 fino ad ottenere segmenti di lunghezza 1: successivamente si riassemblano segmenti di vettori ordinati in un vettore di lunghezza doppia tramite fusione. Per capire come funziona l algoritmo, è necessario descrivere la fusione. La fusione (o merge) si riferisce al problema di ottenere, dati due vettori ordinati, un unico vettore ordinato che contiene gli elementi di entrambi i vettori di partenza. Il vettore risultante sarà di lunghezza pari alla somma delle due lunghezze dei vettori dati La seguente funzione ottiene la fusione di due parti di vettore comprese tra gli indici q e t, e t+1 e r, rispettivamente. Il vettore dato si chiama v, mentre w è un vettore di appoggio. void merge (vettore v, int q, int t, int r) vettore w; int i=q; int j=t+1; int k=q; 1 2 while (i<=t && j<=r) if (v[i]<=v[j]) w[k]=v[i]; i=i+1; Università degli Studi dell Aquila 17
18 w[k]=v[j]; j=j+1; 9 k=k+1; 10 8 if (i<=t) 11 do w[k]=v[i]; k=k+1; 13 i=i+1; 14 while (i<=t); 15 do w[k]=v[j]; k=k+1; 17 j=j+1; 18 while (j<=r); for (k=q; k<=r; k=k+1) v[k]=w[k]; 22 Pongo n=r-q+1 n1=t-q+1 n2=r-t n1+n2=n # istr. costo freq. (c.p.) freq. (c.m.) n n n-1 n1 6 1 n1 n1 7 1 n1 n1 8 1 n n2-1 0 Università degli Studi dell Aquila 18
19 10 1 n-1 n n n n n n+1 n n n 23 1 n n Nel caso peggiore consideriamo il caso in cui il ciclo while ricopia il massimo di elementi (n- 1 elementi), cioè, per semplificare, il caso in cui si alterna la copia di un elemento dal primo e dal secondo vettore: t(n)=6n+2n1+2n2+6= (ponendo n1=n2=n/2) =8n+6 nel caso migliore, consideriamo il caso in cui il primo ciclo ricopia gli elementi solo del primo vettore e mai del secondo, cioè quando gli elementi del primo vettore vengono tutti prima degli elementi del secondo vettore: t(n)=3n+5n1+4n2+7= (ponendo n1=n2=n/2) =15/2 n +7 Il seguente codice realizza l algoritmo di mergesort: void mergesort (vettore v, int q, int r) int t; if (q<r) 1 t=(q+r)/2; 2 mergesort (v,q,t); 3 mergesort (v,t+1,r); merge (v,q,t,r); chiamata: mergesort (v,0,n-1); Università degli Studi dell Aquila 19
20 n=r-q+1 q<r n>1 # istr. costo freq. (n>1) freq. (n=1) t(n/2) t(n/2) n Equazione di ricorrenza: t(n) =2t(n/2)+8n+8 t(1)=1 Per avere un equazione più generale, poniamo: t(n)=2t(n/2)+cn+d Soluzione: t(n/2)=2t(n/4)+cn/2+d t(n)=4t(n/4)+cn+2d+cn+d=4t(n/4)+2cn+3d t(n/4)=2t(n/8)+cn/4+d t(n)=8t(n/8)+cn+4d+2cn+3d=8t(n/8)+3cn+7d t(n/8)=2t(n/16)+cn/8+d t(n)= 16t(n/16)+cn+8d +3cn+7d= 16t(n/16)+4cn+15d. t(n) = n t( 1) log2 n cn ( n 1) d = = cn log 2 n ( d 1) n d = = 8n log2 n 9n 8 Applichiamo l algoritmo a un vettore con numero di elementi pari a una potenza di 2, per descrivere più facilmente il funzionamento. Consideriamo ad esempio il seguente vettore con 8 elementi: v Le chiamate ricorsive determinate dall algoritmo sono schematizzate come nella figura p seguente. Abbiamo un numero di chiamate della funzione mergesort per n 2 pari a: Università degli Studi dell Aquila 20
21 = = p k 2 = 2 p 1 1 k 0 = 2n-1. Il numero di chiamate della funzione merge è 2 p 1 = n-1 E possibile stimare il tempo di calcolo osservando che abbiamo un tempo di esecuzione lineare per ogni livello della figura dovuto alle attivazioni della funzione merge su n elementi. Inoltre i livelli sono pari a p e quindi in totale abbiamo un tempo nlogn. livello livello livello livello livello 2 merge(v,0,0,1) merge(v,2,2,3) merge(v,4,4,5) merge(v,6,6,7) merge(v,0,1,3) merge(v,4,5,7) livello merge(v,0,3,7) livello Università degli Studi dell Aquila 21
22 Quicksort Anche il quicksort è un algoritmo basato su una strategia divide et impera. La suddivisione dell array da ordinare non avviene nel punto di mezzo come nel mergesort, ma attraverso una operazione di partizione che suddivide l array in due parti tali che nella prima parte ci siano tutti i valori minori o uguali a un valore fissato (detto pivot) e nella seconda parte ci siano tutti i valori maggiori o uguali al pivot. La seguente funzione che realizza la partizione dell array sceglie come elemento pivot il primo elemento dell array. La funzione scandisce l array con due indici da estremi opposti, scambiando di volta in volta le coppie di valori che non rispettano la condizione desiderata. Esempio di vettore v con pivot x[0]=8: Università degli Studi dell Aquila 22
23 int partizione (vettore v, int q, int r) int i,j,x ; 1 2 x=v[q] ; i=q-1 ; j=r+1 ; //x pivot while (i<j) do j=j-1 while (v[j]>x); 7 do i=i+1 while (v[i]<x); if (i<j) scambia (v[i],v[j]); 10 return j; 11 Università degli Studi dell Aquila 23
24 Calcolo della t(n): n=r-q+1 # istr. costo freq. (array freq. freq. (suddivisione ordinato) (suddivisione a a metà, con max metà, con 1 solo scambi) scambio) n/ n n/2 n/2 6 1 n n/2 n/ n/2 n/ n/2 n/ n/ n/ Caso peggiore per il quicksort: array ordinato t(n)=2n+9 Caso migliore per il quicksort: suddivisione sempre a metà - con 1 scambio (scambio solo pivot): t(n)=2n+12 - con max scambi: t(n)=9/2 n + 5 La funzione quicksort: void quicksort (vettore v, int q, int r) int t; if (q<r) 1 t=partizione(v,q,r); quicksort (v,q,t); 3 quicksort (v,t+1,r); 2 4 # istr. costo (c.p.) costo (c.m.) freq. (n>1) freq. (n=1) n+9 2n t(1) t(n/2) t(n-1) t(n/2) 1 0 Università degli Studi dell Aquila 24
25 Caso migliore (suddivisione perfettamente bilanciata, la funzione partizione ogni volta divide il vettore a metà): t(n)=2t(n/2) + 2n + 13 t(1)=1 soluzione come il mergesort: t(n) = cn log 2 n ( d 1) n d = 2n log2 n 14n 13. Caso ottimale: Partizione bilanciata Costo n log n pari al numero dei livelli per il costo lineare della partizione: Caso peggiore (array già ordinato e conseguente suddivisione totalmente sbilanciata; ogni chiamata di partizione suddivide il vettore in una parte di un solo elemento e una parte dei restanti elementi): t(n)= t(n-1) + t(1) + 2n +10 t(1)=1 Poniamo: t(n) = t(n-1) + 2n + 11 = t(n-1) + cn +d soluzione: t(n-1)=t(n-2) + c(n -1) +d t(n)=t(n-2) + c(n -1) +d + cn +d =t(n-2)+ c(n -1) + cn +2d t(n-2)=t(n-3) + c(n-2) +d t(n)= t(n-3) + c(n-2) +d + c(n -1) + cn +2d =t(n-3)+ c(n-2) + c(n -1) + cn +3d t(n-3)=t(n-4) + c(n-3) +d t(n)= t(n-4) + c(n-3) +d + c(n-2) + c(n -1) + cn +3d = t(n-4)+c(n-3)+c(n-2)+c(n -1)+cn +4d... t(n)= t(1) + c 2 + c c(n-3)+c(n-2)+c(n -1)+cn + (n-1) d = Università degli Studi dell Aquila 25
26 = 1 + c = 2 n k 2 n 12n 12 k + d (n-1) = 1 + c n(n 2 1) c 2 c - c +d(n-1) = n d n c d Caso peggiore: Partizione sbilanciata Costo quadratico pari al numero dei livelli per il costo lineare della partizione Università degli Studi dell Aquila 26
27 Tabella comparativa dei metodi nlogn di ordinamento: Algoritmo Caso peggiore Caso migliore t(n) ( g ( n)) t(n) ( g ( n)) Mergesort 8n log2 n 9n 8 ( n logn) 8n log2 n 9n 8 ( n logn) 2 Quicksort n 12n 12 ( n 2 ) 2n log2 n 14n 13 ( n logn) Tabella comparativa dei metodi di ordinamento: Caso peggiore Caso medio Caso migliore Mergesort ( n logn) ( n logn) ( n logn) Quicksort ( n 2 ) ( n logn) ( n logn) Selectionsort ( n 2 ) ( n 2 ) ( n 2 ) Insertionsort ( n 2 ) ( n 2 ) (n) Bubblesort ( n 2 ) ( n 2 ) (n) Algoritmi ottimi: Per il problema dell ordinamento, la delimitazione inferiore della complessità è ( n logn). Pertanto, il solo algoritmo ottimo che abbiamo trattato è il mergesort che ha complessità nel caso peggiore ( n logn). Per il problema della ricerca, la delimitazione inferiore della complessità è (logn). Pertanto la ricerca binaria è un algoritmo ottimo perché risolve il problema in tempo (logn). Le notazioni asintotiche si possono applicare anche allo spazio di memoria utilizzato e non solo al tempo. Occupazione di memoria degli algoritmi di ordinamento: Il mergesort ha un occupazione di memoria pari a 2n, mentre per tutti gli altri si ha n. Università degli Studi dell Aquila 27
28 Strutture dati fondamentali (tipi astratti) I tipi astratti sono strutture dati generali di particolare importanza in informatica. Tra di essi abbiamo: insiemi, liste, pile, code, matrici, alberi, grafi. Possiamo studiare le proprietà e le operazioni dei tipi di dato astratto indipendentemente dalla loro realizzazione tramite i tipi offerti dai linguaggi di programmazione Distinguiamo tra tipi astratti e tipi concreti: un tipo astratto può avere più rappresentazioni concrete. Ad esempio, possiamo studiare le liste in generale, ma poi implementarle con diverse tecniche: array statici, array dinamici, liste collegate con record e puntatori, etc. La programmazione con tipi astratti prevede la scrittura di programmi indipendentemente dalla rappresentazione utilizzata. Liste Le liste sono sequenze ordinate di elementi. Per sequenza ordinata si intende un insieme in cui è possibile riconoscere un primo elemento, un secondo, e così via. Si tratta quindi di un ordinamento sulle posizioni degli elementi e non sui loro valori. Quindi i valori all interno di una lista sono in generale disordinati, non rispettando alcun ordinamento particolare, crescente o decrescente. Introduciamo tre rappresentazioni per le liste: Rappresentazione con array Rappresentazione con liste collegate di record e puntatori Rappresentazione con liste collegate bidirezionali Rappresentazione con array Una lista può essere rappresentata con un array. È utile associare a quest ultimo un campo che indica il numero di elementi della lista. L occupazione di memoria è pari a n. Rappresentazione: const int D=100 ; typedef int vettore[d]; struct lista int n ; //numero valori lista vettore valori; //valori lista ; Considerazioni sulla complessità: Università degli Studi dell Aquila 28
29 L accesso a un elemento di una lista rappresentata con un array è ( 1). L inserimento di un elemento in una determinata posizione è (n) nel caso peggiore a causa dello spostamento degli altri elementi. Rappresentazione con liste collegate di record e puntatori Per ogni elemento, abbiamo bisogno di un record con campo valore e campo puntatore al record successivo. L occupazione di memoria è pari a 2n. struct elemento int valore; elemento* succ; ; typedef elemento* lista; //campo valore //campo puntatore al successivo Considerazioni sulla complessità: L accesso a un elemento di una lista collegata è (n) nel caso peggiore, perché bisogna scorrere la lista. L inserimento di un elemento dopo un certo elemento è ( 1), perché non è necessario spostare elementi. Rappresentazione con liste collegate bidirezionali Questa rappresentazione prevede un puntatore all elemento precedente, oltre al puntatore all elemento successivo. Può essere utile per scorrere facilmente la lista in entrambe le direzioni. L occupazione di memoria aumenta ed è pari a 3n. È necessario mantenere due puntatori iniziali, al primo e all ultimo elemento. l struct elemento int valore; elemento* succ; elemento* prec; ; typedef elemento* pelem; struct lista pelem primo; pelem ultimo; //campo valore //campo puntatore al successivo //campo puntatore al precedente Università degli Studi dell Aquila 29
30 ; Vediamo alcune funzioni, come CreaLista e StampaLista: void CreaLista (lista & l, int n) if (n==0) l.primo = NULL; l.ultimo = NULL; if (n>0) l.primo = new elemento; pelem p1; p1=l.primo; p1->prec=null; cout<<"elemento 0="; cin >> p1->valore; for (int i=1;i<n;i++) p1->succ=new elemento; p1->succ->prec=p1; p1=p1->succ; cout<<"elemento "<<i<<"="; cin >> p1->valore; p1->succ=null; l.ultimo=p1; void StampaLista (lista l) if (l.primo!=null) pelem p1=l.primo; while (p1!=null) cout<<p1->valore<<" "; p1=p1->succ ; La funzione StampaListaInv, che in versione iterativa per le liste collegate semplici aveva complessità ( n 2 ), per le liste bidirezionali è (n). void StampaListaInv (lista l) if (l.ultimo!=null) pelem p1=l.ultimo; Università degli Studi dell Aquila 30
31 while (p1!=null) cout<<p1->valore<<" "; p1=p1->prec ; Di seguito si riporta una versione ricorsiva per la creazione di una lista bidirezionale. Sono necessarie due funzioni: la funzione ricorsiva CreaListaRic è richiamata dalla funzione CreaLista: void CreaListaRic (pelem & p, pelem prec, int n, pelem & ultimo) if (n>0) p = new elemento; cin >> p->valore; p->prec=prec; CreaListaRic (p->succ,p,n-1,ultimo); p = NULL; ultimo=prec; void CreaLista (lista & l, int n) CreaListaRic (l.primo, NULL, n, l.ultimo); Operazioni elementari sulle liste Sulle liste non c è un modo univoco di definire le operazioni elementari. Si può seguire la strada di definire un insieme molto ristretto di operazioni, ma questo va spesso a scapito dell efficienza degli algoritmi su liste più complessi a seconda delle rappresentazioni. Un insieme minimale di operazioni può essere il seguente: Inserisci (x, pos, l): inserisce un nuovo elemento con valore x in posizione pos. Deve verificarsi che pos è compresa tra 0 e n. Per pos = 0 abbiamo un inserimento in testa. Per pos = n abbiamo un inserimento in coda. Cancella(pos, l): cancella l elemento in posizione pos, per pos compresa tra 0 e n-1. Per pos = 0 abbiamo la cancellazione in testa. Per pos=n-1 abbiamo la cancellazione in coda. Accedi(pos, l): restituisce il valore dell elemento in posizione pos. Init(l): inizializza una lista vuota. ListaVuota(l): effettua il test di lista vuota. Università degli Studi dell Aquila 31
32 È utile considerare anche le seguenti operazioni elementari per risolvere in maniera efficace alcuni problemi tipici: InsTesta(x, l): inserisce l elemento x in testa alla lista l; InsCoda(x,l): inserisce l elemento x in coda alla lista l; CancTesta(l): cancella l elemento di testa; CancCoda(l): cancella l elemento di coda; AccediTesta(l): restituisce l elemento di testa; AccediCoda(l): restituisce l elemento di coda; numelementi(l): restituisce il numero di elementi di una lista; Copia(l1,l2): copia la lista l1 nella lista l2; CancellaLista(l): cancella l intera lista l. Consideriamo i seguenti prototipi: void Inserisci(int x, int pos, lista & l); void Cancella(int pos, lista & l); int Accedi(int pos, lista l); lista Init(); bool ListaVuota(lista l); void InsTesta(int x, lista & l); void InsCoda(int x, lista & l); void CancTesta(lista & l); void CancCoda(lista & l); int AccediTesta(lista l); int AccediCoda(lista l); int numelementi(lista l); void Copia(lista l1, lista & l2); void CancellaLista(lista & l); Scriviamo alcune funzioni facendo uso delle sole operazioni elementari. La funzione CreaLista: lista CreaLista (int n) int x; lista l=init(); for (int i=0; i<n; i++) cin>>x; Inserisci(x,i,l); return l; La funzione CreaLista fa uso dell operazione Inserisci. Per la rappresentazione con array, scriviamo la funzione relativa: Università degli Studi dell Aquila 32
33 void Inserisci(int x, int pos, lista & l) //inserisce un elemento con valore x in posizione pos. pos è compresa tra 0 e n. Per pos =0 abbiamo un inserimento in testa. Per pos=n abbiamo un inserimento in coda. if (pos<0) cout << pos << "negativo"; if (pos>l.n) cout << pos << " troppo grande"; for (int i=l.n-1;i>=pos;i--) l.valori[i+1]= l.valori[i]; l.valori[pos]=x; //memorizzazione valore x in posizione p l.n++; La complessità nel caso peggiore (corrispondente all inserimento in testa) è (n), mentre nel caso migliore (corrispondente all inserimento in coda) è ( 1). Per la rappresentazione con liste collegate semplici, abbiamo la seguente funzione: void Inserisci(int x, int pos, lista & l) //inserisce un elemento con valore x in posizione pos. pos è compresa tra 0 e n. Per pos =0 abbiamo un inserimento in testa. Per pos=n abbiamo un inserimento in coda. if (pos<0) cout << pos << "negativo"; if (pos==0) elemento* p1=new elemento; p1->valore=x; p1->succ=l; l=p1; elemento* p=l ; for (int i=0 ; p!=null && i<(pos-1); i++) p=p->succ; if (p!=null) elemento * paux; paux=p->succ; p->succ=new elemento ; p=p->succ; p->valore=x ; p->succ=paux ; cout << pos << "troppo grande"; Università degli Studi dell Aquila 33
34 La complessità nel caso peggiore (corrispondente all inserimento in coda) è (n), mentre nel caso migliore (corrispondente all inserimento in testa) è ( 1). La complessità della funzione CreaLista con le due rappresentazioni: 1. nella rappresentazione con array, le chiamate ad Inserisci avvengono inserendo sempre in coda l elemento, che coincide con il caso migliore di Inserisci, pari a ( 1). Complessivamente la CreaLista ha tempo (n) ; 2. Nella rappresentazione con liste collegate, ogni chiamata di Inserisci corrisponde al caso peggiore per questa rappresentazione, cioè (n). Complessivamente si ha ( n 2 ). Nella rappresentazione con liste bidirezionali possiamo avere un miglioramento a patto che usiamo l operazione elementare InsCoda, che ha costo costante, al posto della generica Inserisci: void InsCoda(int x, lista & l) if (l.ultimo==null) l.primo = new elemento; l.primo->prec=null; l.primo->valore=x; l.primo->succ=null; l.ultimo=l.primo; l.ultimo->succ=new elemento; l.ultimo->succ->prec=l.ultimo; l.ultimo=l.ultimo->succ; l.ultimo->valore=x; l.ultimo->succ=null; La funzione CreaLista modificata ha costo lineare con la rappresentazione con liste bidirezionali: lista CreaLista (int n) int x; lista l=init(); for (int i=0; i<n; i++) cin>>x; InsCoda(x,l); return l; Università degli Studi dell Aquila 34
35 Altri esempi: invertire una lista, facendo uso di sole operazioni primitive: void InvertiLista(lista & l) lista l1=init(); int x; while(!listavuota(l)) x=acceditesta(l); CancTesta(l); InsTesta(x,l1); Copia(l1,l); CancellaLista(l1); Concatenare due liste, facendo uso di sole operazioni primitive: void ConcatenaListe(lista & l1, lista & l2, lista & l3) l3=init(); Copia(l1,l3); int x; while(!listavuota(l2)) x=acceditesta(l2); CancTesta(l2); InsCoda(x,l3); CancellaLista(l1); void Fusione(lista & l1, lista & l2, lista & l3) l3=init(); while (!ListaVuota(l1)&&!ListaVuota(l2)) if (AccediTesta(l1)<AccediTesta(l2)) InsCoda(AccediTesta(l1), l3); CancTesta(l1); InsCoda(AccediTesta(l2), l3); CancTesta(l2); Università degli Studi dell Aquila 35
36 while(!listavuota(l1)) InsCoda(AccediTesta(l1),l3); CancTesta(l1); while(!listavuota(l2)) InsCoda(AccediTesta(l2),l3); CancTesta(l2); Scrivere una funzione che, data una lista contenente valori ordinati in senso crescente, crei una nuova lista senza i valori ripetuti (per esempio, se la prima lista contiene i valori 2, 4, 4, 6, 7, 7, 8, al termine della funzione la seconda lista dovrà contenere i valori 2, 4, 6, 7, 8). La prima lista deve rimanere invariata. Si deve fare uso di sole operazioni primitive su liste. Qual è la complessità computazionale? void CreaSenzaRipetuti(lista l, lista & l1) int x=acceditesta(l); l1=init(); InsTesta(x,l1); for(int i=1;i<numelementi(l);i++) x=accedi(i,l); if (x!=accedicoda(l1)) InsCoda(x,l1); Nel caso della rappresentazione con array, le operazioni primitive utilizzate hanno tutte costo ( 1). Pertanto la complessità computazionale, determinata dal costo del ciclo, è (n). Nel caso della rappresentazione con liste collegate, le operazioni primitive presenti in questa funzione hanno un costo (n), determinando una complessità della funzione pari a ( n 2 ). Scrivere una funzione che, data una lista contenente valori ordinati in senso crescente, cancelli dalla lista i valori ripetuti (per esempio, se la lista contiene i valori 2, 4, 4, 6, 7, 7, 8, al termine della funzione la lista dovrà contenere i valori 2, 4, 6, 7, 8). Si deve fare uso di sole operazioni primitive su liste. Qual è la complessità computazionale? Soluzione a: void CancellaValoriRipetuti(lista & l) int x=acceditesta(l); lista l1=init(); InsTesta(x,l1); for(int i=1;i<numelementi(l);i++) Università degli Studi dell Aquila 36
37 x=accedi(i,l); if (x!=accedicoda(l1)) InsCoda(x,l1); CancellaLista(l); Copia(l1,l); Soluzione b: void CancellaValoriRipetuti(lista & l) int i=0; while (i<numelementi(l)-1) if (Accedi(i,l)==Accedi(i+1,l)) Cancella(i+1,l); i++; Data una lista, scrivere una funzione che trasferisca in una nuova lista gli elementi che contengono valori maggiori di un dato intero x. Pertanto la lista data non deve più contenere al termine della funzione gli elementi trasferiti. Inoltre la lista creata deve contenere i valori trasferiti nello stesso ordine in cui si trovavano nella lista data. Si deve fare uso di sole operazioni primitive su liste. Qual è la complessità computazionale? soluzione: void TrasferisciValoriMaggiori(lista & l, int x, lista & l1) int elem; lista l2=init(); while (!ListaVuota(l)) elem=acceditesta(l); if (elem>x) InsCoda(elem,l1); InsCoda(elem,l2); CancellaTesta(l); Copia(l2,l); CancellaLista(l2); Università degli Studi dell Aquila 37
38 Nel caso della rappresentazione con array, l operazione primitiva più costosa all interno del ciclo è CancellaTesta che ha costo (n). Pertanto la complessità computazionale, determinata dal costo del ciclo, è ( n 2 ). Nel caso della rappresentazione con liste collegate, l operazione primitiva più costosa all interno del ciclo è InsCoda che ha costo (n), determinando una complessità della funzione pari a ( n 2 ). Codifica operazioni primitive nella rappresentazione con array lista Init() lista l; l.n=0; return l; int Accedi(int pos, lista l) if (pos<0) cout << pos << "negativo"; if (pos>l.n) cout << pos << " troppo grande"; return l.valori[pos]; int AccediTesta(lista l) if (l.n==0) cout << "lista vuota"; return l.valori[0]; int AccediCoda(lista l) if (l.n==0) cout << "lista vuota"; return l.valori[l.n-1]; bool ListaVuota(lista l) return (l.n==0); Università degli Studi dell Aquila 38
39 void Inserisci(int x, int pos, lista & l) //inserisce un elemento con valore x in posizione pos. pos è //compresa tra 0 e n. Per pos =0 abbiamo un inserimento in //testa. Per pos=n abbiamo un inserimento in coda. if (pos<0) cout << pos << "negativo"; if (pos>l.n) cout << pos << " troppo grande"; for (int i=l.n-1;i>=pos;i--) l.valori[i+1]=l.valori[i]; l.valori[pos]=x; //memorizzazione valore x in //posizione p l.n++; void InsTesta(int x, lista & l) for (int i=l.n-1;i>=0;i--) l.valori[i+1]=l.valori[i]; l.valori[0]=x; //memorizzazione valore x in posizione 0 l.n++; void InsCoda(int x, lista & l) l.valori[l.n]=x; //memorizzazione valore x in posizione l.n l.n++; void Cancella(int pos, lista & l) if (l.n==0) cout << "lista vuota"; for (int i=pos;i<l.n-1;i++) l.valori[i]=l.valori[i+1]; l.n--; void CancTesta(lista & l) if (l.n==0) cout << "lista vuota"; Università degli Studi dell Aquila 39
40 for (int i=0;i<l.n-1;i++) l.valori[i]=l.valori[i+1]; l.n--; int numelementi(lista l) return l.n; void Copia(lista l1, lista & l2) for (int i=0;i<l1.n;i++) l2.valori[i]=l1.valori[i]; l2.n=l1.n; void CancellaLista(lista & l) l.n=0; Codifica operazioni primitive nella rappresentazione con liste collegate lista Init() lista l; l=null; return l; int Accedi(int pos, lista l) if (pos<0) cout << pos << "negativo"; if (pos==0) return l->valore; Università degli Studi dell Aquila 40
41 elemento* p=l ; for (int i=0 ; p!=null && i<pos; i++) p=p->succ; if (p!=null) return p->valore; cout << pos << "troppo grande"; int AccediTesta(lista l) if (l==null) cout << "lista vuota"; return l->valore; bool ListaVuota(lista l) return (l==null); void Inserisci(int x, int pos, lista & l) //inserisce un elemento con valore x in posizione pos. pos è compresa tra 0 e n. Per pos =0 abbiamo un inserimento in testa. Per pos=n abbiamo un inserimento in coda. if (pos<0) cout << pos << "negativo"; if (pos==0) elemento* p1=new elemento; p1->valore=x; p1->succ=l; l=p1; elemento* p=l ; for (int i=0 ; p!=null && i<(pos-1); i++) p=p->succ; if (p!=null) elemento* paux; paux=p->succ; Università degli Studi dell Aquila 41
42 p->succ=new elemento ; p=p->succ; p->valore=x ; p->succ=paux ; cout << pos << "troppo grande"; void InsTesta(int x, lista & l) elemento* p1=new elemento; p1->valore=x; p1->succ=l; l=p1; void InsCoda(int x, lista & l) if (l==null) //lista nulla l=new elemento; l->valore=x; l->succ=null; elemento* paux; paux=l; while (paux->succ!=null) paux=paux->succ; paux->succ=new elemento; paux=paux->succ; paux->valore=x; paux->succ=null; void CancTesta(lista & l) if (l!=null) elemento* paux=l; l=l->succ; delete paux; Università degli Studi dell Aquila 42
43 int numelementi(lista l) int i=0; while (l!=null) l=l->succ; i++; return i; void Copia(lista l1, lista & l2) if (l1==null) l2=null; l2 = new elemento; l2->valore=l1->valore; elemento *p1=l1->succ, *p2=l2; while (p1!=null) p2->succ=new elemento; p2=p2->succ; p2->valore=p1->valore; p1=p1->succ; p2->succ=null; void CancellaLista(lista & l) elemento *p=l; while (l!=null) l=l->succ; delete p; p=l; Università degli Studi dell Aquila 43
44 Pile e code Pile e code sono sequenze ordinate di elementi (come le liste) in cui si disciplina la strategia di accesso. La lettura di un elemento di queste strutture dati, così come la cancellazione di un elemento o l inserimento di un nuovo elemento, avvengono con delle regole ben precise. Pile Nella pila ( stack in inglese), l accesso è limitato ad una sola estremità della sequenza. Esiste quindi un elemento affiorante (l elemento top della pila) a cui è possibile accedere, mentre non è possibile accedere agli altri elementi, se non rimuovendo l elemento affiorante. L operazione di cancellazione dalla pila dell elemento affiorante si chiama pop, mentre l operazione di inserimento di un nuovo elemento al di sopra dell elemento affiorante si chiama push. Questa strategia di accesso per le pile va sotto il nome di LIFO (last in first out): l ultimo elemento ad entrare in una pila sarà il primo ad uscirne Le pile sono strutture dati molto comuni in informatica. Ad esempio, la gestione della memoria per le chiamate a funzioni avviene tramite uno stack di sistema. Nello stack sono depositate le informazioni relative alle chiamate di funzioni. L ultima funzione ad essere chiamata sarà quella affiorante nello stack. Ad esempio, nel caso di chiamate ricorsive, l ultima chiamata sarà anche la prima ad essere completata. In totale, possiamo definire cinque operazioni primitive su pile: Crea(p): inizializza una nuova pila p; Top(p): accede all elemento affiorante della pila p; Push(x,p): aggiunge un elemento x alla pila p; Pop(p): rimuove un elemento dalla pila p; Vuota(p): compie il test di pila vuota. Università degli Studi dell Aquila 44
45 Codifichiamo queste operazioni con le seguenti funzioni, supponendo di aver già dichiarato un tipo pila ed un tipo elemento : pila CreaPila(); elemento Top(pila p); void Push(elemento x, pila & p); void Pop(pila & p); bool PilaVuota(pila p); Con queste operazioni primitive, possiamo costruire qualsiasi algoritmo che opera su pile. Ad esempio, vogliamo leggere e cancellare l ultimo elemento di una pila. Allo scopo, abbiamo bisogno di una pila di appoggio: pila p=creapila(); //riempimento della pila p pila p1=creapila(); elemento x; while(!pilavuota(p)) x=top(p); Pop(p); Push(x,p1); x=top(p1); Stampa(x); Pop(p1); while(!pilavuota(p1)) x=top(p1); Pop(p1); Push(x,p); Università degli Studi dell Aquila 45
46 Rappresentazioni per le pile Le pile possono essere rappresentate in vari modi. Esaminiamo una rappresentazione con array e una con liste collegate. Rappresentazione con array 3 top const int D=100 ; typedef int elemento; //dipende dalla definizione dell elemento typedef elemento vettore[d]; struct pila int top ; //indice elemento top, se -1 pila vuota vettore elementi; //elementi pila ; Vediamo come le operazioni primitive sono implementate con questa rappresentazione: pila CreaPila() pila p; p.top=-1; return p; elemento Top(pila p) if (p.top==-1) cout<< Pila vuota ; return p.elementi[p.top]; void Push(elemento x, pila & p) if (p.top==d-1) cout<< Pila piena ; p.elementi[p.top+1]=x; Università degli Studi dell Aquila 46
47 p.top++; void Pop(pila & p) if (p.top==-1) cout<< Pila vuota ; p.top--; bool PilaVuota(pila p) return (p.top==-1); L operazione primitiva Push può dar luogo ad un errore se l array è tutto pieno. Scriviamo una funzione per la memorizzazione di n valori letti da tastiera in una pila: pila LeggiPila(int n) pila p; p=creapila(); elemento x; for (int i=0;i<n;i++) cout<<"elemento "<<i<<"="; cin >> x; Push(x,p); return p; Scriviamo una funzione per la stampa su video degli elementi di una pila. Notiamo che la funzione non svuota la pila perché il parametro è passato per valore: quindi la funzione svuota una copia della pila originaria. void ScriviPila(pila p) elemento x; while(!pilavuota(p)) x=top(p); cout << x << ; Pop(p); Università degli Studi dell Aquila 47
48 Rappresentazione con liste collegate typedef int elemento; //dipende dalla definizione dell elemento struct record elemento valore; record* succ; ; typedef record* pila; pila In questa rappresentazione, il puntatore iniziale alla lista punta all elemento affiorante della pila. Vediamo la codifica delle operazioni primitive con questa rappresentazione. pila CreaPila() pila p; p=null; return p; elemento Top(pila p) if (p==null) cout<< Pila vuota ; return p->valore; void Push(elemento x, pila & p) record* paux=new record; paux->valore=x; paux->succ=p; p=paux; void Pop(pila & p) if (p==null) cout<< Pila vuota ; record* paux=p; p=p->succ; delete paux ; bool PilaVuota(pila p) return (p==null); Università degli Studi dell Aquila 48
49 Con questa rappresentazione, la funzione scritta in precedenza per la stampa degli elementi di una pila non funziona correttamente dato che essa causa lo svuotamento della pila stessa. Non è infatti possibile effettuare la copia della lista collegata passando il parametro per valore. Quindi la funziona ScriviPila va riscritta, salvando gli elementi in una pila di appoggio man mano che vengono estratti dalla pila data, e poi ricostituendo la pila originaria: void ScriviPila(pila & p) elemento x; pila p1=creapila(); while(!pilavuota(p)) x=top(p); cout << x << " "; Pop(p); Push(x,p1); while(!pilavuota(p1)) x=top(p1); Pop(p1); Push(x,p); In entrambe le rappresentazioni viste, le operazioni primitive sulle pile hanno un tempo di esecuzione costante. La funzione ScriviPila ha un tempo di esecuzione lineare. Università degli Studi dell Aquila 49
50 Code Nelle code ( queue in inglese), l accesso in ingresso è limitato ad una estremità della sequenza, mentre l accesso in uscita all altra estremità. Dal lato in uscita, c è il solo elemento che è possibile esaminare (l elemento front della coda). L operazione di cancellazione dalla coda di tale elemento si chiama pop, mentre l operazione di inserimento di un nuovo elemento nell altra estremità si chiama push. Questa strategia di accesso per le code va sotto il nome di FIFO (first in first out): il primo elemento ad entrare in una coda sarà il primo ad uscirne Le code sono strutture dati molto comuni in informatica. Ad esempio, molte funzioni del sistema operativo per la gestione delle periferiche si basano sulle code. Varie richieste da più utenti o programmi per l uso di una stampante saranno gestite con una coda: la richiesta che arriva per prima sarà servita per prima. In totale, possiamo definire cinque operazioni primitive su code: Crea(c): inizializza una nuova coda c; Front(c): accede all elemento affiorante della coda c; Push(x,c): aggiunge un elemento x alla coda c; Pop(c): rimuove un elemento dalla coda c; Vuota(c): compie il test di coda vuota. Codifichiamo queste operazioni con le seguenti funzioni, supponendo di aver già dichiarato un tipo coda ed un tipo elemento : coda CreaCoda(); elemento Front(coda c); void Push(elemento x, coda & c); void Pop(coda & c); bool CodaVuota(coda c); Con queste operazioni primitive, possiamo costruire qualsiasi algoritmo che opera su code. Supponiamo di voler svuotare una coda e stampare gli elementi sul video: coda c=creacoda(); //riempimento della coda c elemento x; while(!codavuota(c)) x=front(c); Stampa(x); Pop(c); Università degli Studi dell Aquila 50
51 Rappresentazioni per le code Le pile possono essere rappresentate in vari modi. Esaminiamo due rappresentazioni con array e una con liste collegate. Prima rappresentazione con array Gli elementi sono inseriti alla fine del vettore ed estratti all inizio. Le due estremità sono indicate con due indici front e last. L indice front rappresenta l elemento da estrarre dalla coda e l indice last l ultimo elemento arrivato. Se l indice last è inferiore all indice front, si ha la coda vuota. Inizialmente, l indice last è posto a -1 e l indice front a 0. Quando l indice last raggiunge la fine dell array, è necessaria una traslazione all indietro di tutti gli elementi della coda front last const int D=100 ; typedef int elemento; //dipende dalla definizione dell elemento typedef elemento vettore[d]; struct coda int front ; //indice elemento front int last ; //indice elemento ultimo vettore elementi; //elementi coda ; Vediamo come le operazioni primitive sono implementate con questa rappresentazione: coda CreaCoda () coda c; c.last=-1; c.front=0; return c; elemento Front(coda c) if (c.last<c.front) cout<< Coda vuota ; return c.elementi[c.front]; Università degli Studi dell Aquila 51
Il tipo di dato astratto Pila
Il tipo di dato astratto Pila Il tipo di dato Pila Una pila è una sequenza di elementi (tutti dello stesso tipo) in cui l inserimento e l eliminazione di elementi avvengono secondo la regola seguente:
DettagliDue algoritmi di ordinamento. basati sulla tecnica Divide et Impera: Mergesort e Quicksort
Due algoritmi di ordinamento basati sulla tecnica Divide et Impera: Mergesort e Quicksort (13 ottobre 2009, 2 novembre 2010) Ordinamento INPUT: un insieme di n oggetti a 1, a 2,, a n presi da un dominio
Dettagli10 - Programmare con gli Array
10 - Programmare con gli Array Programmazione e analisi di dati Modulo A: Programmazione in Java Paolo Milazzo Dipartimento di Informatica, Università di Pisa http://www.di.unipi.it/ milazzo milazzo di.unipi.it
DettagliGESTIONE INFORMATICA DEI DATI AZIENDALI
GESTIONE INFORMATICA DEI DATI AZIENDALI Alberto ZANONI Centro Vito Volterra Università Tor Vergata Via Columbia 2, 00133 Roma, Italy zanoni@volterra.uniroma2.it Rudimenti di programmazione Programming
DettagliCorso di Tecniche di Programmazione
Corso di Tecniche di Programmazione Corsi di Laurea in Ingegneria Informatica ed Automatica Anno Accedemico 003/004 Proff. Giuseppe De Giacomo, Luca Iocchi, Domenico Lembo Dispensa : Algoritmi di Ordinamento
DettagliLa struttura dati ad albero binario
La struttura dati ad albero binario L albero è una struttura dati nella quale le informazioni sono organizzate in modo gerarchico, dall alto verso il basso. Gli elementi di un albero si chiamano nodi,
DettagliAlgoritmi e strutture dati. Codici di Huffman
Algoritmi e strutture dati Codici di Huffman Memorizzazione dei dati Quando un file viene memorizzato, esso va memorizzato in qualche formato binario Modo più semplice: memorizzare il codice ASCII per
DettagliAA 2006-07 LA RICORSIONE
PROGRAMMAZIONE AA 2006-07 LA RICORSIONE AA 2006-07 Prof.ssa A. Lanza - DIB 1/18 LA RICORSIONE Il concetto di ricorsione nasce dalla matematica Una funzione matematica è definita ricorsivamente quando nella
DettagliEsercizi per il corso di Algoritmi e Strutture Dati
1 Esercizi per il corso di Algoritmi e Strutture Dati Esercizi sulla Tecnica Divide et Impera N.B. Tutti gli algoritmi vanno scritti in pseudocodice (non in Java, né in C++, etc. ). Di tutti gli algoritmi
DettagliSOMMARIO Coda (queue): QUEUE. QUEUE : specifica QUEUE
SOMMARIO Coda (queue): Specifica: interfaccia. Implementazione: Strutture indicizzate (array): Array di dimensione variabile. Array circolari. Strutture collegate (nodi). Prestazioni. Strutture Software
DettagliAlgoritmi di Ricerca. Esempi di programmi Java
Fondamenti di Informatica Algoritmi di Ricerca Esempi di programmi Java Fondamenti di Informatica - D. Talia - UNICAL 1 Ricerca in una sequenza di elementi Data una sequenza di elementi, occorre verificare
DettagliSono casi particolari di MCF : SPT (cammini minimi) non vi sono vincoli di capacità superiore (solo x ij > 0) (i, j) A : c ij, costo di percorrenza
Il problema di flusso di costo minimo (MCF) Dati : grafo orientato G = ( N, A ) i N, deficit del nodo i : b i (i, j) A u ij, capacità superiore (max quantità di flusso che può transitare) c ij, costo di
DettagliCorso di Laurea Ingegneria Informatica Fondamenti di Informatica 2
Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2 Dispensa E08 Soluzione Esercizi F. Gasparetti, C. Limongelli Marzo 2008 http://www.dia.uniroma3.it/~java/fondinf1/ Soluzione Esercizi
DettagliRicerche, ordinamenti e fusioni. 5.1 Introduzione. 5.2 Ricerca completa
Ricerche, ordinamenti e fusioni 5.1 Introduzione Questo capitolo ci permette di fare pratica di programmazione utilizzando gli strumenti del linguaggio introdotti finora. A una prima lettura possono essere
DettagliStrutture. Strutture e Unioni. Definizione di strutture (2) Definizione di strutture (1)
Strutture Strutture e Unioni DD cap.10 pp.379-391, 405-406 KP cap. 9 pp.361-379 Strutture Collezioni di variabili correlate (aggregati) sotto un unico nome Possono contenere variabili con diversi nomi
Dettaglivoid funzioneprova() { int x=2; cout<<"dentro la funzione x="<<x<<endl; }
FUNZIONI 57. Cosa servono le funzioni? A spezzare il programma in diverse parti relativamente indipendenti fra loro, ovvero interagenti sono attraverso i parametri di input ed IL VALORE di uscita. In questo
DettagliPROBLEMA DELLA RICERCA DI UN ELEMENTO IN UN ARRAY E ALGORITMI RISOLUTIVI
PROBLEMA DELLA RICERCA DI UN ELEMENTO IN UN ARRAY E ALGORITMI RISOLUTIVI PROBLEMA DELLA RICERCA in termini generali: Dati in input un insieme S di elementi (numeri, caratteri, stringhe, ) e un elemento
DettagliAPPUNTI DI MATEMATICA LE FRAZIONI ALGEBRICHE ALESSANDRO BOCCONI
APPUNTI DI MATEMATICA LE FRAZIONI ALGEBRICHE ALESSANDRO BOCCONI Indice 1 Le frazioni algebriche 1.1 Il minimo comune multiplo e il Massimo Comun Divisore fra polinomi........ 1. Le frazioni algebriche....................................
DettagliAlgoritmi e Strutture Dati
schifano@fe.infn.it Laurea di Informatica - Università di Ferrara 2011-2012 [1] Strutture dati Dinamiche: Le liste Una lista è una sequenza di elementi di un certo tipo in cui è possibile aggiungere e/o
Dettagli1. PRIME PROPRIETÀ 2
RELAZIONI 1. Prime proprietà Il significato comune del concetto di relazione è facilmente intuibile: due elementi sono in relazione se c è un legame tra loro descritto da una certa proprietà; ad esempio,
DettagliCorso di Informatica
Corso di Informatica Modulo T Scorrimento-Rotazione-Ricerca Prerequisiti Programmazione elementare Conoscenza ed uso di vettori Introduzione Lo scopo di questa Unità è approfondire il concetto di vettore
DettagliFunzioni in C. Violetta Lonati
Università degli studi di Milano Dipartimento di Scienze dell Informazione Laboratorio di algoritmi e strutture dati Corso di laurea in Informatica Funzioni - in breve: Funzioni Definizione di funzioni
DettagliI tipi di dato astratti
I tipi di dato astratti.0 I tipi di dato astratti c Diego Calvanese Fondamenti di Informatica Corso di Laurea in Ingegneria Elettronica A.A. 001/00.0 0 I tipi di dato astratti La nozione di tipo di dato
DettagliProgrammazione dinamica
Capitolo 6 Programmazione dinamica 6.4 Il problema della distanza di edit tra due stringhe x e y chiede di calcolare il minimo numero di operazioni su singoli caratteri (inserimento, cancellazione e sostituzione)
DettagliDimensione di uno Spazio vettoriale
Capitolo 4 Dimensione di uno Spazio vettoriale 4.1 Introduzione Dedichiamo questo capitolo ad un concetto fondamentale in algebra lineare: la dimensione di uno spazio vettoriale. Daremo una definizione
Dettagli4 3 4 = 4 x 10 2 + 3 x 10 1 + 4 x 10 0 aaa 10 2 10 1 10 0
Rappresentazione dei numeri I numeri che siamo abituati ad utilizzare sono espressi utilizzando il sistema di numerazione decimale, che si chiama così perché utilizza 0 cifre (0,,2,3,4,5,6,7,8,9). Si dice
DettagliComplessità Computazionale
Complessità Computazionale Analisi Algoritmi e pseudocodice Cosa significa analizzare un algoritmo Modello di calcolo Analisi del caso peggiore e del caso medio Esempio di algoritmo in pseudocodice INSERTION
Dettagli4.1 Modelli di calcolo analisi asintotica e ricorrenze
4 Esercizi Prima Parte 4.1 Modelli di calcolo analisi asintotica e ricorrenze Esercizio 4 1 Rispondere alle seguenti domande: 1. Come misuriamo l efficienza di un algoritmo?. Quali sono gli algoritmi più
DettagliEsercizi Capitolo 6 - Alberi binari di ricerca
Esercizi Capitolo 6 - Alberi binari di ricerca Alberto Montresor 23 settembre 200 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente, è possibile
DettagliNote su quicksort per ASD 2010-11 (DRAFT)
Note su quicksort per ASD 010-11 (DRAFT) Nicola Rebagliati 7 dicembre 010 1 Quicksort L algoritmo di quicksort è uno degli algoritmi più veloci in pratica per il riordinamento basato su confronti. L idea
DettagliUniversità di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A. 2013-14. Pietro Frasca.
Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A. 2013-14 Pietro Frasca Lezione 11 Martedì 12-11-2013 1 Tecniche di allocazione mediante free list Generalmente,
DettagliESERCIZI DI PROBLEM SOLVING E COMPOSIZIONE DEI DIAGRAMMI DI FLUSSO per le classi terza
ESERCIZI DI PROBLEM SOLVING E COMPOSIZIONE DEI DIAGRAMMI DI FLUSSO per le classi terza vers.3 in lavorazione Docente SAFFI FABIO Contenuti 01.Esercizi generici sul diagramma di flusso - flow chart... 2
DettagliMatematica generale CTF
Successioni numeriche 19 agosto 2015 Definizione di successione Monotonìa e limitatezza Forme indeterminate Successioni infinitesime Comportamento asintotico Criterio del rapporto per le successioni Definizione
DettagliCorrispondenze e funzioni
Corrispondenze e funzioni L attività fondamentale della mente umana consiste nello stabilire corrispondenze e relazioni tra oggetti; è anche per questo motivo che il concetto di corrispondenza è uno dei
DettagliFONDAMENTI di INFORMATICA L. Mezzalira
FONDAMENTI di INFORMATICA L. Mezzalira Possibili domande 1 --- Caratteristiche delle macchine tipiche dell informatica Componenti hardware del modello funzionale di sistema informatico Componenti software
DettagliPlate Locator Riconoscimento Automatico di Targhe
Progetto per Laboratorio di Informatica 3 - Rimotti Daniele, Santinelli Gabriele Plate Locator Riconoscimento Automatico di Targhe Il programma plate_locator.m prende come input: l immagine della targa
DettagliEsempio: dest = parolagigante, lettere = PROVA dest (dopo l'invocazione di tipo pari ) = pprrlogvgante
Esercizio 0 Scambio lettere Scrivere la funzione void scambiolettere(char *dest, char *lettere, int p_o_d) che modifichi la stringa destinazione (dest), sostituendone i caratteri pari o dispari (a seconda
DettagliB+Trees. Introduzione
B+Trees Introduzione B+Trees Il B+Trees e la variante maggiormente utilizzata dei BTrees BTrees e B+trees fanno parte della famiglia degli alberi di ricerca. Nel B+Trees i dati sono memorizzati solo nelle
DettagliINTRODUZIONE AGLI ALGORITMI INTRODUZIONE AGLI ALGORITMI INTRODUZIONE AGLI ALGORITMI INTRODUZIONE AGLI ALGORITMI
INTRODUZIONE AGLI ALGORITMI Prima di riuscire a scrivere un programma, abbiamo bisogno di conoscere un metodo risolutivo, cioè un metodo che a partire dai dati di ingresso fornisce i risultati attesi.
DettagliStrutturazione logica dei dati: i file
Strutturazione logica dei dati: i file Informazioni più complesse possono essere composte a partire da informazioni elementari Esempio di una banca: supponiamo di voler mantenere all'interno di un computer
DettagliAppunti sulla Macchina di Turing. Macchina di Turing
Macchina di Turing Una macchina di Turing è costituita dai seguenti elementi (vedi fig. 1): a) una unità di memoria, detta memoria esterna, consistente in un nastro illimitato in entrambi i sensi e suddiviso
DettagliSoluzione dell esercizio del 2 Febbraio 2004
Soluzione dell esercizio del 2 Febbraio 2004 1. Casi d uso I casi d uso sono riportati in Figura 1. Figura 1: Diagramma dei casi d uso. E evidenziato un sotto caso di uso. 2. Modello concettuale Osserviamo
DettagliINFORMATICA 1 L. Mezzalira
INFORMATICA 1 L. Mezzalira Possibili domande 1 --- Caratteristiche delle macchine tipiche dell informatica Componenti hardware del modello funzionale di sistema informatico Componenti software del modello
DettagliIntroduzione alla programmazione in C
Introduzione alla programmazione in C Testi Consigliati: A. Kelley & I. Pohl C didattica e programmazione B.W. Kernighan & D. M. Ritchie Linguaggio C P. Tosoratti Introduzione all informatica Materiale
DettagliDefinire all'interno del codice un vettore di interi di dimensione DIM, es. int array[] = {1, 5, 2, 4, 8, 1, 1, 9, 11, 4, 12};
ESERCIZI 2 LABORATORIO Problema 1 Definire all'interno del codice un vettore di interi di dimensione DIM, es. int array[] = {1, 5, 2, 4, 8, 1, 1, 9, 11, 4, 12}; Chiede all'utente un numero e, tramite ricerca
DettagliCOGNOME E NOME (IN STAMPATELLO) MATRICOLA
Politecnico di Milano Facoltà di Ingegneria dell Informazione Informatica 3 Proff. Ghezzi, Lanzi, Matera e Morzenti Seconda prova in itinere 4 Luglio 2005 COGNOME E NOME (IN STAMPATELLO) MATRICOLA Risolvere
DettagliCorso di Matematica per la Chimica
Dott.ssa Maria Carmela De Bonis a.a. 203-4 I sistemi lineari Generalità sui sistemi lineari Molti problemi dell ingegneria, della fisica, della chimica, dell informatica e dell economia, si modellizzano
DettagliLaboratorio di programmazione
Laboratorio di programmazione Lezione VI Tatiana Zolo tatiana.zolo@libero.it 1 LE STRUCT Tipo definito dall utente i cui elementi possono essere eterogenei (di tipo diverso). Introduce un nuovo tipo di
DettagliConcetto di Funzione e Procedura METODI in Java
Fondamenti di Informatica Concetto di Funzione e Procedura METODI in Java Fondamenti di Informatica - D. Talia - UNICAL 1 Metodi e Sottoprogrammi Mentre in Java tramite le classi e gli oggetti è possibile
DettagliSequenziamento a minimo costo di commutazione in macchine o celle con costo lineare e posizione home (In generale il metodo di ottimizzazione
Sequenziamento a minimo costo di commutazione in macchine o celle con costo lineare e posizione home (In generale il metodo di ottimizzazione presentato in questo file trova la seq. a costo minimo per
DettagliA intervalli regolari ogni router manda la sua tabella a tutti i vicini, e riceve quelle dei vicini.
Algoritmi di routing dinamici (pag.89) UdA2_L5 Nelle moderne reti si usano algoritmi dinamici, che si adattano automaticamente ai cambiamenti della rete. Questi algoritmi non sono eseguiti solo all'avvio
DettagliTesti di Esercizi e Quesiti 1
Architettura degli Elaboratori, 2009-2010 Testi di Esercizi e Quesiti 1 1. Una rete logica ha quattro variabili booleane di ingresso a 0, a 1, b 0, b 1 e due variabili booleane di uscita z 0, z 1. La specifica
DettagliEsercizi su. Funzioni
Esercizi su Funzioni ๒ Varie Tracce extra Sul sito del corso ๓ Esercizi funz_max.cc funz_fattoriale.cc ๔ Documentazione Il codice va documentato (commentato) Leggibilità Riduzione degli errori Manutenibilità
DettagliRICERCA DI UN ELEMENTO
RICERCA DI UN ELEMENTO Si legga da tastiera un array di N elementi (N stabilito dall utente) Si richieda un elemento x il programma deve cercare l elemento x nell array Se l elemento è presente, deve visualizzare
DettagliAlgebra di Boole: Concetti di base. Fondamenti di Informatica - D. Talia - UNICAL 1. Fondamenti di Informatica
Fondamenti di Informatica Algebra di Boole: Concetti di base Fondamenti di Informatica - D. Talia - UNICAL 1 Algebra di Boole E un algebra basata su tre operazioni logiche OR AND NOT Ed operandi che possono
DettagliRicerca Operativa Esercizi sul metodo del simplesso. Luigi De Giovanni, Laura Brentegani
Ricerca Operativa Esercizi sul metodo del simplesso Luigi De Giovanni, Laura Brentegani 1 1) Risolvere il seguente problema di programmazione lineare. ma + + 3 s.t. 2 + + 2 + 2 + 3 5 2 + 2 + 6,, 0 Soluzione.
DettagliI file di dati. Unità didattica D1 1
I file di dati Unità didattica D1 1 1) I file sequenziali Utili per la memorizzazione di informazioni testuali Si tratta di strutture organizzate per righe e non per record Non sono adatte per grandi quantità
DettagliCorso di Informatica
Corso di Informatica Modulo T3 1-Sottoprogrammi 1 Prerequisiti Tecnica top-down Programmazione elementare 2 1 Introduzione Lo scopo di questa Unità è utilizzare la metodologia di progettazione top-down
DettagliUna funzione è detta ricorsiva se chiama, direttamente o indirettamente, se stessa. In C tutte le funzioni possono essere usate ricorsivamente.
Ricorsione Funzioni ricorsive Una funzione è detta ricorsiva se chiama, direttamente o indirettamente, se stessa. In C tutte le funzioni possono essere usate ricorsivamente. Un esempio di funzione ricorsiva
DettagliInformatica 3. LEZIONE 21: Ricerca su liste e tecniche di hashing. Modulo 1: Algoritmi sequenziali e basati su liste Modulo 2: Hashing
Informatica 3 LEZIONE 21: Ricerca su liste e tecniche di hashing Modulo 1: Algoritmi sequenziali e basati su liste Modulo 2: Hashing Informatica 3 Lezione 21 - Modulo 1 Algoritmi sequenziali e basati su
DettagliLe query di raggruppamento
Le query di raggruppamento Le "Query di raggruppamento" sono delle Query di selezione che fanno uso delle "Funzioni di aggregazione" come la Somma, il Conteggio, il Massimo, il Minimo o la Media, per visualizzare
DettagliSommario. Definizione di informatica. Definizione di un calcolatore come esecutore. Gli algoritmi.
Algoritmi 1 Sommario Definizione di informatica. Definizione di un calcolatore come esecutore. Gli algoritmi. 2 Informatica Nome Informatica=informazione+automatica. Definizione Scienza che si occupa dell
DettagliSTRUTTURE NON LINEARI
PR1 Lezione 13: STRUTTURE NON LINEARI Michele Nappi mnappi@unisa.it www.dmi.unisa.it/people/nappi Per la realizzazione della presentazione è stato utilizzato in parte materiale didattico prodotto da Oronzo
DettagliMatematica in laboratorio
Unità 1 Attività guidate Attività 1 Foglio elettronico Divisibilità tra numeri naturali Costruisci un foglio di lavoro per determinare se a è divisibile per b, essendo a e b due numeri naturali, con a
DettagliCapitolo 2. Operazione di limite
Capitolo 2 Operazione di ite In questo capitolo vogliamo occuparci dell operazione di ite, strumento indispensabile per scoprire molte proprietà delle funzioni. D ora in avanti riguarderemo i domini A
DettagliTipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:
Tipi primitivi Il linguaggio Java offre alcuni tipi di dato primitivi Una variabile di tipo primitivo può essere utilizzata direttamente. Non è un riferimento e non ha senso tentare di istanziarla mediante
DettagliRisolvere un problema significa individuare un procedimento che permetta di arrivare al risultato partendo dai dati
Algoritmi Algoritmi Risolvere un problema significa individuare un procedimento che permetta di arrivare al risultato partendo dai dati Il procedimento (chiamato algoritmo) è composto da passi elementari
DettagliInformatica 3. LEZIONE 23: Indicizzazione. Modulo 1: Indicizzazione lineare, ISAM e ad albero Modulo 2: 2-3 trees, B-trees e B + -trees
Informatica 3 LEZIONE 23: Indicizzazione Modulo 1: Indicizzazione lineare, ISAM e ad albero Modulo 2: 2-3 trees, B-trees e B + -trees Informatica 3 Lezione 23 - Modulo 1 Indicizzazione lineare, ISAM e
DettagliRICORSIVITA. Vediamo come si programma la soluzione ricorsiva al problema precedente: Poniamo S 1 =1 S 2 =1+2 S 3 =1+2+3
RICORSIVITA 1. Cos è la ricorsività? La ricorsività è un metodo di soluzione dei problemi che consiste nell esprimere la soluzione relativa al caso n in funzione della soluzione relativa al caso n-1. La
DettagliGli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori
Gli array Array e puntatori Laboratorio di Informatica I un array è un insieme di elementi (valori) avente le seguenti caratteristiche: - un array è ordinato: agli elementi dell array è assegnato un ordine
DettagliCalcolare il massimo di una lista
Calcolare il massimo di una lista Ieri abbiamo imparato a calcolare il massimo di una lista predefinita: lista = [4,24,-89,81,3,0,-12,31] max = lista[0] # questo e' un commento: primo elemento di lista
DettagliEsercizi Capitolo 2 - Analisi di Algoritmi
Esercizi Capitolo - Analisi di Algoritmi Alberto Montresor 19 Agosto, 014 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente, è possibile saltare
DettagliLa distribuzione Normale. La distribuzione Normale
La Distribuzione Normale o Gaussiana è la distribuzione più importante ed utilizzata in tutta la statistica La curva delle frequenze della distribuzione Normale ha una forma caratteristica, simile ad una
DettagliAlessandro Pellegrini
Esercitazione sulle Rappresentazioni Numeriche Esistono 1 tipi di persone al mondo: quelli che conoscono il codice binario e quelli che non lo conoscono Alessandro Pellegrini Cosa studiare prima Conversione
DettagliCluster. Vicino alla temperatura critica gli spin formano grandi gruppi (cluster)
Cluster Vicino alla temperatura critica gli spin formano grandi gruppi (cluster) all interno di ogni gruppo è molto improbabile riuscire a flippare uno spin perché ci sarebbe una grande perdita di energia,
DettagliAlgoritmi e diagrammi di flusso
Algoritmi e diagrammi di flusso Un algoritmo può essere descritto come una sequenza finita ed ordinata di operazioni che descrivono la soluzione di un problema. Per sequenza finita si intende che un algoritmo
DettagliUniversità degli Studi di Ferrara - A.A. 2014/15 Dott. Valerio Muzzioli ORDINAMENTO DEI DATI
ORDINAMENTO DEI DATI Quando si ordina un elenco (ovvero una serie di righe contenenti dati correlati), le righe sono ridisposte in base al contenuto di una colonna specificata. Distinguiamo due tipi di
DettagliALGEBRA DELLE PROPOSIZIONI
Università di Salerno Fondamenti di Informatica Corso di Laurea Ingegneria Corso B Docente: Ing. Giovanni Secondulfo Anno Accademico 2010-2011 ALGEBRA DELLE PROPOSIZIONI Fondamenti di Informatica Algebra
DettagliLaboratorio di Calcolatori 1 Corso di Laurea in Fisica A.A. 2006/2007
Laboratorio di Calcolatori 1 Corso di Laurea in Fisica A.A. 2006/2007 Dott.Davide Di Ruscio Dipartimento di Informatica Università degli Studi di L Aquila Lezione del 08/03/07 Nota Questi lucidi sono tratti
DettagliEsempi di algoritmi. Lezione III
Esempi di algoritmi Lezione III Scopo della lezione Implementare da zero algoritmi di media complessità. Verificare la correttezza di un algoritmo eseguendolo a mano. Imparare a valutare le prestazioni
DettagliIntroduzione al MATLAB c Parte 2
Introduzione al MATLAB c Parte 2 Lucia Gastaldi Dipartimento di Matematica, http://dm.ing.unibs.it/gastaldi/ 18 gennaio 2008 Outline 1 M-file di tipo Script e Function Script Function 2 Costrutti di programmazione
DettagliAlgoritmi su array / 2
Corso di Informatica Algoritmi su array / Anno Accademico / Francesco Tortorella Algoritmi su array Operazioni tipiche sugli array: inizializzazione lettura stampa ricerca del minimo e del massimo ricerca
DettagliAnalisi di scenario File Nr. 10
1 Analisi di scenario File Nr. 10 Giorgio Calcagnini Università di Urbino Dip. Economia, Società, Politica giorgio.calcagnini@uniurb.it http://www.econ.uniurb.it/calcagnini/ http://www.econ.uniurb.it/calcagnini/forecasting.html
DettagliSiamo così arrivati all aritmetica modulare, ma anche a individuare alcuni aspetti di come funziona l aritmetica del calcolatore come vedremo.
DALLE PESATE ALL ARITMETICA FINITA IN BASE 2 Si è trovato, partendo da un problema concreto, che con la base 2, utilizzando alcune potenze della base, operando con solo addizioni, posso ottenere tutti
Dettagli4. Operazioni elementari per righe e colonne
4. Operazioni elementari per righe e colonne Sia K un campo, e sia A una matrice m n a elementi in K. Una operazione elementare per righe sulla matrice A è una operazione di uno dei seguenti tre tipi:
DettagliInformatica 3. Informatica 3. LEZIONE 10: Introduzione agli algoritmi e alle strutture dati. Lezione 10 - Modulo 1. Importanza delle strutture dati
Informatica 3 Informatica 3 LEZIONE 10: Introduzione agli algoritmi e alle strutture dati Modulo 1: Perchè studiare algoritmi e strutture dati Modulo 2: Definizioni di base Lezione 10 - Modulo 1 Perchè
DettagliCorso di Fondamenti di Informatica Algoritmi su array / 2
Corso di Fondamenti di Informatica Algoritmi su array / Anno Accademico 00/009 Francesco Tortorella Algoritmi su array Operazioni tipiche sugli array: inizializzazione lettura stampa ricerca del minimo
DettagliAllocazione dinamica della memoria - riepilogo
Università degli studi di Milano Dipartimento di Scienze dell Informazione Laboratorio di algoritmi e strutture dati Corso di laurea in Informatica In breve Storage duration Allocazione dinamica della
Dettagli13. Campi vettoriali
13. Campi vettoriali 1 Il campo di velocità di un fluido Il concetto di campo in fisica non è limitato ai fenomeni elettrici. In generale il valore di una grandezza fisica assegnato per ogni punto dello
Dettagli1 Applicazioni Lineari tra Spazi Vettoriali
1 Applicazioni Lineari tra Spazi Vettoriali Definizione 1 (Applicazioni lineari) Si chiama applicazione lineare una applicazione tra uno spazio vettoriale ed uno spazio vettoriale sul campo tale che "!$%!
DettagliAppunti tratti dal videocorso on-line di Algoritmi e Programmazione Avanzata By ALeXio
Appunti tratti dal videocorso on-line di Algoritmi e Programmazione Avanzata By ALeXio 1-La memoria dinamica La scrittura di un programma (indipendentemente dal linguaggio adottato) deve sempre tener conto
Dettagli3 GRAFICI DI FUNZIONI
3 GRAFICI DI FUNZIONI Particolari sottoinsiemi di R che noi studieremo sono i grafici di funzioni. Il grafico di una funzione f (se non è specificato il dominio di definizione) è dato da {(x, y) : x dom
DettagliLe stringhe. Le stringhe
Informatica: C++ Gerboni Roberta Stringhe di caratteri (esempi di utilizzo dei vettori) Nel linguaggio C++ una stringa è semplicemente un vettore di caratteri Vettori di caratteri La stringa "hello" è
DettagliMODULO 5 ACCESS Basi di dati. Lezione 4
MODULO 5 ACCESS Basi di dati Lezione 4 ARGOMENTI Lezione 4 Filtrare i dati Esempio 1 Query Cos è Creare Query in visualizza struttura Criteri di ricerca Esempio 2 Esempio 3 Esempio 4 Creare Query in creazione
DettagliCorso di Informatica Generale (C. L. Economia e Commercio) Ing. Valerio Lacagnina Rappresentazione in virgola mobile
Problemi connessi all utilizzo di un numero di bit limitato Abbiamo visto quali sono i vantaggi dell utilizzo della rappresentazione in complemento alla base: corrispondenza biunivoca fra rappresentazione
DettagliLa selezione binaria
Andrea Marin Università Ca Foscari Venezia Laurea in Informatica Corso di Programmazione part-time a.a. 2011/2012 Introduzione L esecuzione di tutte le istruzioni in sequenza può non è sufficiente per
DettagliUso di base delle funzioni in Microsoft Excel
Uso di base delle funzioni in Microsoft Excel Le funzioni Una funzione è un operatore che applicato a uno o più argomenti (valori, siano essi numeri con virgola, numeri interi, stringhe di caratteri) restituisce
Dettagli16.3.1 Alberi binari di ricerca
442 CAPITOLO 16. STRUTTURE DI DATI DINAMICHE root 7 5 11 2 8 13 10 Figura 16.11 Esempio di albero binario: ogni nodo contiene il dato da immagazzinare e tre puntatori che definiscono le sue relazioni di
DettagliUniversità di Torino Facoltà di Scienze MFN Corso di Studi in Informatica. Programmazione I - corso B a.a. 2009-10. prof.
Università di Torino Facoltà di Scienze MFN Corso di Studi in Informatica Programmazione I - corso B a.a. 009-10 prof. Viviana Bono Blocco 9 Metodi statici: passaggio parametri, variabili locali, record
Dettagli3 CENNI DI TEORIA DELLA COMPLESSITA COMPUTAZIONALE. E. Amaldi Fondamenti di R.O. Politecnico di Milano 1
3 CENNI DI TEORIA DELLA COMPLESSITA COMPUTAZIONALE E. Amaldi Fondamenti di R.O. Politecnico di Milano 1 Scopo: Stimare l onere computazionale per risolvere problemi di ottimizzazione e di altra natura
Dettagli