Gli algoritmi di Ricerca e di Ordinamento
|
|
|
- Alessandra Catalano
- 9 anni fa
- Просмотров:
Транскрипт
1 Gli algoritmi di Ricerca e di Ordinamento Sabrina Mantaci A.A Gli algoritmi di ricerca Il problema della ricerca è il seguente: dato un insieme V di oggetti di un certo tipo, e un altro oggetto x dello stesso tipo, stabilire se x V. Ci proponiamo di scrivere un programma che risolve questo problema. Prima di tutto quando abbiamo a che fare con un problema complesso, ci dobbiamo domandare come rappresentare il nostro insieme. Infatti potremmo rappresentarlo mediante un tipo strutturato set, mediante un array, mediante una lista concatenata, mediante un albero, etc. In realtà quest osservazione non è banale, visto che questo problema può essere impostato su ciascuna di queste strutture, con performances diverse che vedremo via via. Per il momento vediamo come il problema può essere risolto utilizzando un vettore come struttura dati per rappresentare il nostro insieme. Supponiamo quindi di avere strutturato i nostri dati (per esempio interi) in un vettore V e di voler verificare se un certo intero x è contenuto o meno nel vettore. Scriviamo quindi una funzione a valori booleani che presi in input (ossia come parametri) un vettore di interi e un numero intero, restituisce TRUE se l elemento è contenuto nel vettore, e FALSE altrimenti. I parametri saranno ovviamente passati per valore, visto che il problema non richiede di effettuare alcuna modifica nè nel vettore, nè nell elemento da cercare. La funzione sarà la seguente: Function ricercalineare(v:vettore; x:integer):boolean; var i:integer; trovato:boolean; i:=1; trovato:=false; while (i<=n) and (trovato=false) do if V[i]=x then trovato:=true else i:=i+1 ricercalineare:=trovato; 1
2 La funzione ricercalineare ha una complessità di tempo che dipende dal numero di volte in cui durante lo svolgimento della funzione vengono effettuate le istruzioni del ciclo. Il caso peggiore può essere individuato come quello in cui l elemento x non appartiene all insieme, perchè in questo caso è necessario scandire tutto il vettore. In questo caso si è costretti a compiere n iterazioni, per cui la complessità dell algoritmo è O(n) nel caso peggiore. Per inciso, è questo il motivo per cui è denominata ricerca lineare. Tuttavia, se gli elementi del vettore sono ordinati dal più piccolo al più grande possiamo fare di meglio. In questo caso infatti si può osservare che è possibile terminare la ricerca lineare con risposta FALSE nel momento in cui procedendo da sinistra verso destra troviamo un elemento più grande di x. Infatti se gli elementi sono ordinati, appena troviamo un elemento del vettore più grande di x, tutti quelli alla sua destra saranno ancora più grandi. Questo ci autorizza a dire che x non è contenuto nell insieme. Il programma diventa il seguente: Function ricercalineare(v:vettore; x:integer):boolean; var i:integer; trovato:boolean; i:=1; trovato:=false; while (i<=n) and (trovato=false) do if V[i]=x then trovato:=true else if V[i]>x then i:=n+1 else i:=i+1 ricercalineare:=trovato; Tuttavia anche se in media la situazione migliora nei casi in cui x non appartiene al vettore, la complessità di tempo di questa funzione resta O(n) nel caso peggiore. Infatti l elemento x potrebbe trovarsi nell ultima posizione del vettore, oppure essere maggiore di tutti gli elementi del vettore, e questo comporterebbe comunque una scansione di tutto il vettore. Invece, nel caso in cui il vettore è ordinato, possiamo sfruttare quest ipotesi supplementare per operare in maniera diversa e ottenere un grande vantaggio in termini di tempo di calcolo. Confrontiamo l elemento x con quello che si trova a metà del vettore. Se in quel punto c è l elemento cercato, la funzione termina e restituisce il valore TRUE. In caso contrario, ci sono due possibili casi: o è maggiore, o è minore dell elemento a metà del vettore. Se x è minore di questo elemento, allora possiamo essere sicuri che se c è si troverà nella prima metà del vettore, poichè gli elementi nella seconda metà sono tutti maggiori di x. Viceversa, se x è più grande di quest elemento, cercheremo x nella seconda metà del vettore. Questo comporta che ad ogni iterazione scartiamo metà dei confronti possibili. Questa intuitivamente è la ragione per cui si ottiene un grande miglioramento 2
3 della complessità. La funzione che implementa quest algoritmo, che chiameremo ricerca binaria, è la seguente: Function ricercabinaria(v:vettore; x:integer):boolean; var i, j, m: integer; trovato: boolean; i:=1; j:=n; trovato:=false; while (i<>j) and (trovato=false) do m:=(i+j) div 2; if V[m]=x then trovato:=true else if V[i]>x then j:=m-1 else i:=m+1 ricercabinaria:=trovato; Con quest algoritmo, ogni volta che si fa un confronto viene eliminata la metà degli elementi rimanenti. Quindi il numero dei confronti effettuati è uguale al numero di volte che possiamo dividere la dimensione iniziale n per 2 fino ad arrivare ad uno. Questo numero è il logaritmo in base 2 di n. Dunque quest algoritmo ha una complessità di tempo O(log 2 n). Questo algoritmo è chiaramente molto più efficiente del precedente, visto che f(n) = log 2 n è una funzione che al crescere di n, cresce molto più lentamente della funzione g(n) = n. Per avere un idea di questa differenza, si pensi al tempo che occorre a trovare un nome nell elenco telefonico (ordinato) utilizzando il metodo di ricerca che istintivamente utilizziamo, e che è di tipo binario, e a quanto tempo occorrerebbe per trovare un nome se l elenco telefonico non fosse ordinato. Ovviamente nell algoritmo ricercabinaria viene pesantemente utilizzata l ipotesi che il vettore sia ordinato. Non si può quindi applicare la ricerca binaria in mancanza di quest ipotesi. Si noti che questo algoritmo ha per definizione stessa una forma ricorsiva: Function ricercabinaria(v:vettore; x,primo,ultimo:integer):integer; var m:integer; if primo=ultimo then if V[primo]=x then RICERCABINARIA=TRUE else RICERCABINARIA=FALSE; else m:=(primo+ultimo) div 2; if V[m]=x then trovato:=true 3
4 else if V[m]>x then ricercabinaria:=ricercabinaria(v,x,primo,m-1) else ricercabinaria:=ricercabinaria(v,x,m+1,ultimo) Si lascia come esercizio di scrivere un programma ricorsivo che realizzi la ricerca lineare. 4
5 2 Algoritmi di ordinamento Definizione 2.1 Dato un insieme X, una relazione R sull insieme X è un insieme di coppie di elementi di X. Detto in altre parole, R è un sottoinsieme dei prodotto cartesiano X X. Definizione 2.2 Diciamo che una relazione R su un insieme X è una relazione d ordine se i suoi elementi godono delle proprietà antisimmetrica e transitiva. Ossia: per ogni coppia di elementi x, y X le condizioni xry e yrx implicano che x = y (proprietà antisimmetrica); xry e yrz allora xrz (proprietà transitiva). Una relazione R su un insieme X si dice relazione d ordine totale se comunque presi due elementi x, y X, o xry oppure yrx. Definizione 2.3 Diciamo che un insieme X è totalmente ordinato se è possibile definire una relazione d ordine totale R fra i suoi elementi. Esempio: 1. I numeri interi, i numeri relativi, i numeri razionali, i numeri reali, rispetto alla relazione sono insiemi totalmente ordinati; 2. Le lettere dell alfabeto, rispetto all ordine alfabetico. 3. Dato un insieme finito Σ, detto alfabeto, definiamo Σ l insieme di tutte le sequenze finite di elementi di Σ, che chiamiamo parole o stringhe. Data una parola u Σ, denotiamo con u i l i-esimo carattere di u e con u la lunghezza di u. Su Σ si può definire l ordine lessicografico. L ordine lessicografico è definito nel modo seguente: date due parole u, v Σ, diciamo che u lex v se: esiste un k tale che u i = v i per ogni i k u = k e v > k (ossia u è prefisso di v); oppure esiste un k tale che u i = v i per ogni i k e u k+1 < v k+1 (ossia u e v sono uguali fino al k esimo carattere, ma il (k + 1)-esimo carattere di u è più piccolo del (k + 1)-esimo carattere di v). L ordine lessicografico è una relazione d ordine totale su Σ. 4. La relazione di inclusione fra i sottoinsiemi di un insieme è una relazione d ordine (verificare), ma non è una relazione d ordine totale. Infatti possiamo avere due sottoinsiemi di X che non sono in relazione di inclusione uno con l altro. 5
6 Sia dato un insieme di elementi A = {a 1, a 2,..., a n }, presi da un insieme totalmente ordinato. Il problema dell ordinamento (o, in inglese sorting) consiste nel trovare una permutazione σ degli indici {1, 2,..., n} tale che a σ(1) a σ(2) a σ(n) Per risolvere il problema del sorting esistono diversi metodi, ciascuno dei quali ha dei pregi e dei difetti. In mancanza di ipotesi supplementari, tutti gli algoritmi di sorting sono basati su confronti degli elementi dell insieme. Per avere un algoritmo di sorting efficiente, dobbiamo cercare di limitare il numero di confronti. Ma fino a che punto è possibile limitare il numero di questi confronti? Tutti gli algoritmi di sorting basati su confronti rispettano il seguente teorema fondamentale: Teorema 2.1 [Lower bound per gli algoritmi di sorting] Nessun algoritmo di sorting basato su confronti può avere complessità di tempo worst case inferiore a O(n log 2 n). Ossia un qualunque algoritmo di ordinamento basato su confronti deve svolgere necessariamente almeno O(n log 2 n) confronti, se applicato a un generico vettore. 2.1 Algoritmo di ordinamento per selezione (selection sort) Il primo algoritmo che esaminiamo è quello più immediato. Supponiamo che i nostri dati siano organizzati in un array A = [a 1, a 2,..., a n ]. L idea del selectionsort è la seguente: 1. si determina l elemento più piccolo di tutto il vettore; 2. lo si scambia con l elemento in prima posizione del vettore 3. si cerca il secondo elemento più piccolo lo si scambia con l elemento in seconda posizione del vettore; 4. si procede così fino a quando l intero vettore è ordinato. Esempio: Supponiamo di avere il seguente array A : Al primo passo, l algoritmo deve cercare l elemento più piccolo del vettore e piazzarlo nella prima posizione. Con una scansione del vettore verifichiamo che il minimo del vettore è il 4 che si trova nella posizione 6. Scambiamo dunque A[1] e A[6] Alla seconda iterazione verrà cercato il secondo elemento più piccolo del vettore, che è il 6, che si trova nella posizione 3. Alla fine della seconda iterazione A[2] e A[3] vengono scambiati. Così via in tutte le altre iterazioni: 6
7 i= i= i= i= i= Si ottiene quindi: La procedura che implementa l algoritmo di selectionsort sarà la seguente: Procedure selectionsort (var V:vettore); var i, j:integer; procedure scambia(var x,y:integer); var aux:integer; aux:=x; x:=y; y:=aux; for i:=1 to n do indmin:=i; for j:=i+1 to n do if V[j]<V[indmin] then indmin:=j scambia (V[i],V[indmin]) 7
8 Qual è la complessità di quest algoritmo? Dobbiamo contare il numero di confronti effettuati. Nella prima iterazione vengono svolti n 1 confronti per trovare il minimo, nella seconda n 2 confronti per trovare il secondo minimo,..., nella i-esima n i confronti,..., nella (n 1)-esima 1 confronto. Dunque in totale avremo: Dunque l algoritmo è O(n 2 ). n 1 T (n) = i = n(n 1)/2 i=1 Definizione 2.4 Un algoritmo dice adattivo se la complessità di tempo della sua esecuzione dipende dall input. Si dice non adattivo nel caso contrario. Si può notare che nel selectionsort il numero di confronti effettuati dall algoritmo è indipendente dal tipo di input. Per esempio se il vettore è ordinato sin dall inizio, l algoritmo non si accorge che non deve fare nessuno scambio prima di avere svolto tutti i confronti. Il selectionsort è quindi un algoritmo non adattivo. Definizione 2.5 Un algoritmo di sorting si dice stabile se gli elementi che hanno lo stesso valore appaiono dopo l applicazione dell algoritmo nello stesso ordine relativo in cui si trovavano nel vettore iniziale. L importanza di questa proprietà sta nel fatto che a volte gli ordinamenti vengono fatti secondo una chiave di un record (un particolare insieme di dati relativi ad una stessa entità). Supponiamo per esempio di voler ordinare un elenco di persone secondo il loro cognome, e per quelle persone che hanno lo stesso cognome, secondo l ordine dei loro nomi. Supponiamo di avere già ordinato i nomi. Se poi ordiniamo secondo i cognomi, vogliamo che venga rispettato, per tutte le persone che hanno uno stesso cognome, l ordine sui nomi che era stato ottenuto in precedenza. In questo caso occorre che il secondo ordinamento venga effettuato mediante un ordinamento stabile. Detto questo, possiamo osservare che l algoritmo di selectionsort descritto non è stabile. Consideriamo ad esempio il seguente vettore che contiene due elementi uguali: Per chiarezza indichiamo con 4 1 il 4 che compare in posizione 1 e con 4 2 quello che compare in posizione Alla prima iterazione l elemento nella prima posizione verrà scambiato col minimo, ossia il valore 2 che si trova alla quarta posizione
9 All iterazione successiva, il 4 che si trova nella posizione 2 non verrà spostato, poichè è il minimo degli elementi rimanenti. Alla terza iterazione il 4 che si trova alla prima posizione verrà scambiato con l elemento in posizione Dopo questa iterazione i 4 alla posizione 2 e 3 sono nella loro posizione definitiva, ma come si evince dagli indici, si trovano in ordine inverso rispetto all ordine in cui si trovavano all inizio. Dunque l algoritmo non è stabile. 2.2 Bubblesort L algoritmo di sorting che andiamo a descrivere è basato sulla seguente idea. Si scandisce il vettore da sinistra a destra, confrontando ogni elemento con quello adiacente, e scambiandoli se il primo è maggiore del secondo. Ci si rende conto subito che una sola scansione del vettore non basta. Per esempio consideriamo il seguente vettore: consideriano la prima scansione del vettore: il primo confronto viene fatto tra il 23 e il 14. Il 23 è maggiore del 14, dunque i due elementi vengono scambiati il 23 viene confrontato col 6. Essendo più grande, viene scambiato quindi confrontiamo il 23 col 12 e li scambiamo il 23 è confrontato col 34, e questa volta non viene effettuato nessuno scambio Si passa quindi all elemento successivo, il 34, che viene confrontato col 4, e vengono scambiati. quindi si scambia il 34 col
10 Quindi il 34 viene scambiato col 20. seguente: Il vettore alla fine della prima scansione sarà il È evidente che il vettore non è ancora ordinato, ma possiamo osservare che, comunque sia fatto il vettore, l elemento più grande trova la sua posizione definitiva, ossia l ultima posizione. È per questo che l algoritmo si chiama Bubblesort, o ordinamento a bolle, poichè l elemento più grande affiora in superficie come le bolle nell acqua. Ma allora possiamo prevedere che alla prossima iterazione il secondo elemento più grande si troverà alla penultima posizione. In generale, alla i-esima iterazione l i-esimo elemento più grande sarà piazzato alla posizione n i + 1. Questo ci dice che dopo al più n 1 iterazioni, il vettore sarà completamente ordinato. In prima approssimazione la procedura che implementa il bubblesort è la seguente: procedure bubblesort (var V:vettore); var i,j:integer; procedure scambia(var x,y:integer); var aux:integer; aux:=x; x:=y; y:=aux; for i:= 1 to n do for j:= 1 to n-1 do if V[j]>V[j+1] then scambia (V[j],V[j+1]); In realtà alcune iterazioni potrebbero essere superflue. Infatti se a una certa iterazione il vettore fosse già ordinato, basterebbe una sola ulteriore iterazione per accorgersi che non è più necessario nessuno scambio, e quindi il vettore è ordinato e l algoritmo può terminare. Questo può essere controllato trasformando il ciclo esterno in un ciclo repeat-until, utilizzando una variabile booleana che verifica se nella iterazione precedente è stato effettuato uno scambio. procedure bubblesort (var V:vettore); var i,j:integer; scambio:boolean; 10
11 procedure scambia(var x,y:integer); var aux:integer; aux:=x; x:=y; y:=aux; repeat scambio:=false for j:= 1 to n-1 do if V[j]>V[j+1] then scambia (V[j],V[j+1]); scambio:=true; until scambio=false Nel caso peggiore vengono fatte comunque n iterazioni esterne. Possiamo anche osservare che, visto che all i-esima iterazione gli ultimi i elementi del vettore sono nella loro posizione definitiva, possiamo interrompere il ciclo interno dopo n i iterazioni. Questo si può realizzare riducendo di un unità la variabile n alla fine del ciclo interno procedure bubblesort (var V:vettore); var i,j:integer; scambio:boolean procedure scambia(var x,y:integer); var aux:integer; aux:=x; x:=y; y:=aux; repeat scambio:=false for j:= 1 to n-1 do if V[j]>V[j+1] then scambia (V[j],V[j+1]); scambio:=true; 11
12 n:=n-1; until scambio=false Ma si può fare ancora di meglio. Infatti se in una iterazione interna da un certo punto in poi non vengono effettuati scambi, significa che tali valori si trovano nella loro posizione definitiva. Questo può essere controllato tenendo traccia della posizione in cui è effettuato l ultimo scambio, e far sì che il successivo ciclo for termini in questa posizione. procedure bubblesort (var V:vettore); var i,j,p:integer; scambio:boolean procedure scambia(var x,y:integer); var aux:integer; aux:=x; x:=y; y:=aux; p:=n; repeat scambio:=false for j:= 1 to n-1 do if V[j]>V[j+1] then scambia (V[j],V[j+1]); scambio:=true; p:=j+1 n:=p; until scambio=false Si può notare che, malgrado tutte le ottimizzazioni effettuate migliorino in media le prestazioni dell algoritmo, nel caso peggiore (che è per quest algoritmo quello in cui il vettore da ordinare è ordinato in senso inverso), si devono effettuare nella prima iterazione n 1 confronti e scambi, nella seconda n 2, e così via. In totale verranno svolte n (n 1)/2 operazioni di confronto e/o scambio. Anche questo algoritmo è quindi un algoritmo di tempo quadratico O(n 2 ) nel caso peggiore. Tuttavia, per quanto osservato prima, questo algoritmo si arresta non appena il vettore diventa ordinato. In casi particolarmente fortunati il numero di confronti può essere vicino 12
13 ad n. Questo algoritmo è quindi un algoritmo adattivo. Inoltre l algoritmo è stabile in quanto elementi con la stessa chiave non vengono mai invertiti. Infine anche questo algoritmo lavora in loco, ossia non utilizza nessun vettore ausiliario, dunque nessuno spazio di memoria supplementare. 2.3 Mergesort Un altro metodo per il sorting utilizza la tecnica algoritmica del divide et impera (dividi e governa o, in inglese, divide and conquer). Secondo questa tecnica l input viene diviso in due o più parti più piccole e l algoritmo viene applicato ricorsivamente a ciascuna delle parti in cui è diviso l input. In particolare questo metodo di sorting, chiamato mergesort, consiste nel dividere il vettore in due parti e operare ricorsivamente un ordinamento su ciascuna delle due parti. Nella fase di ricostruzione occorre fondere (merge) due vettori ordinati in un unico vettore ordinato. Vediamo cosa succede su un esempio: Esempio: Supponiamo di volere ordinare il seguente array: Il vettore viene suddiviso in due vettori di taglia metà: A sua volta, ciascuno di essi viene diviso a metà e ancora una volta a metà A un certo punto si arriva ad avere tanti array di taglia 1. Tali array sono ovviamente ordinati. Il nostro scopo è quello di costruire un vettore ordinato di taglia 2k a partire da due vettori ordinati di taglia k. Al primo passo è molto semplice. Confrontiamo i primi due vettori, nel nostro esempio quello costituito dal solo elemento 23 e quello costituito dal solo elemento 14. Se vogliamo costruire un vettore di taglia 2 con tali elementi ordinati, basta un singolo confronto per stabilire che 14 < 23, e quindi collocare il 14 prima di 23. Lo stesso si fa per le coppie (6, 12), (34, 4), (15, 20). Si ottengono dunque i seguenti vettori:
14 A questo punto vogliamo unificare in un unico vettore ordinato i primi due vettori (ordinati). Dobbiamo quindi trovare il minimo valore contenuto nei due vettori per trovare quale deve essere inserito come primo elemento nel nuovo vettore. Visto che i due vettori di partenza sono ordinati, l elemento più piccolo sarà sicuramente o il primo del primo vettore o il primo del secondo vettore. Con un solo confronto riusciamo a stabilire quant è il minimo. Nella fattispecie è il 6, e lo mettiamo in prima posizione. A questo punto il secondo elemento più piccolo sarà o il primo del primo vettore o il secondo del secondo vettore. In questo caso è il 12, e lo inseriamo in seconda posizione. Essendo che il secondo vettore è esaurito, gli elementi rimanenti del primo vettore vanno ordinatamente inseriti nel nuovo vettore. Lo stesso procedimento può essere adottato per le coppie (4, 34), (15, 20). Otteniamo la seguente configurazione: A questo punto restano da fondere gli ultimi due vettori utilizzando la stessa tecnica vista prima. Si ottiene quindi: La procedura mergesort farà quindi uso di una procedura ausiliaria (che chiameremo merge) che, presi in input due vettori ordinati di taglia k, genera un vettore di taglia 2k. La procedura in realtà lavora su una porzione di vettore, e utilizza una variabile locale B di tipo vettore, che ci servirà come vettore ausiliario. Vengono passati come parametri il vettore V, e gli interi l,m,r, che rappresentano le due porzioni di vettore adiacenti che stiamo analizzando ossia l intervallo [l,m] e l intervallo [m+1,r]. Si suppone che gli elementi dell intervallo [l,m] e quelli dell intervallo [m+1,r] del vettore siano ordinati. Alla fine della procedure vogliamo che gli elementi dell intervallo [l,r] siano tutti ordinati. La seguente procedura implementa questo algoritmo: l m r procedure merge (var V:vettore, l,m,r:integer); var i,j,k:integer; i:=l; k:=l; j:=m+1; While (i<=m) and (j<=r) do if V[i]<=V[j] then B[k]:=V[i]; 14
15 i:=i+1; k:=k+1; end else B[k]:=V[j]; j:=j+1; k:=k+1; while i<=m do B[k]:=V[i]; i:=i+1; k:=k+1; while j<=r do B[k]:=V[j]; j:=j+1; k:=k+1; for k:=l to r do V[k]:=B[k] La procedura mergesort farà uso di questa procedura. L idea è quella accennata nell esempio, ossia considerato un vettore, si divide a metà e si applica ricorsivamente la procedura mergesort a ciascuna delle due metà. Una volta che i due sottoarray sono ordinati, si fondono mediante la procedura merge: procedure mergesort (var V:vettore, l,r:integer); var m:integer; m:=(l+r) div 2; mergesort(v,l,m); mergesort(v,m+1,r); merge(v,l,m,r) Andiamo ora a calcolare la complessità. Prima di tutto consideriamo la complessità della procedura merge. Per ogni elemento che viene inserito nel vettore B si applica tempo costante. Infatti si svolge al più un confronto e l elemento più piccolo viene copiato nel vettore B. In totale dunque la sua complessità è dell ordine della taglia della porzione di vettore che si sta ordinando. 15
16 Andiamo alla procedura mergesort. Ad ogni passo vengono applicate due chiamate ricorsive del mergesort, a due vettori della taglia metà del vettore iniziale, più una chiamata alla procedura merge. Un modo per calcolare la complessità è calcolare la funzione ricorsiva T (n) che calcola la complessità di mergesort su un vettore di taglia n. T (n) = 2T (n/2) + n = 2(2T (n/4) + n/2) + n = = 4T (n/4) + n + n = 4(2T (n/8) + 1/4) + n + n = = 8T (n/8) + n + n + n = = n } + n + {{ + n } = n log n log n volte Dunque la complessità dell algoritmo è O(n log n). Un altro modo più intuitivo per calcolare questa complessità è il seguente: un vettore può essere diviso a metà un numero di volte uguale al logaritmo della sua taglia. La fase divide dell algoritmo costa tempo costante ad ogni chiamata ricorsiva. La ricostruzione di un vettore di taglia 2k a partire da due vettori di taglia k costa O(k). Possiamo però osservare che ad ogni livello di divisione abbiamo un numero di array da fondere tale che la somma di tutte le taglie dei sottovettori è uguale ad n. Dunque la composizione costa O(n) ad ogni livello. Essendoci log n livelli, la complessità totale dell algoritmo è O(n log n). Questo algoritmo utilizza della memoria ausiliaria (il vettore B), dunque non lavora in loco. Inoltre possiamo osservare che questo algoritmo svolge le stesse operazioni per qualunque vettore di input. Questo significa che l algoritmo è non adattivo. Inoltre questo algoritmo non scambia mai l ordine di due elementi con chiavi uguali. Segue che il mergesort è un algoritmo stabile. 2.4 Quicksort Un altro algoritmo di sorting è il quicksort o ordinamento rapido. Questo algoritmo si chiama così perché è quello che in media ha le performances migliori rispetto ad altri algoritmi, anche se non ha la migliore complessità nel caso pessimo. È quello che si chiama un algoritmo randomizzato, in quanto la sua esecuzione dipende da un valore che viene estratto in maniera più o meno casuale. Illustreremo qui un modo di estrarre questo numero, in dipendenza di alcuni valori del vettore, ma non è questo l unico modo. Il quicksort funziona come segue. Supponiamo di voler ordinare un insieme di interi. Si estrae a sorte un numero intero, che possibilmente appartenga al range degli elementi del vettore. Per fare questo potremmo scegliere tale elemento, detto pivot, come la media di due elementi del vettore, per esempio il primo e l ultimo. si riarrangiano gli elementi del vettore in maniera tale che nella parte iniziale del vettore ci siano tutti gli elementi più piccoli del pivot e nella parte finale tutti gli elementi più grandi del pivot. Alla fine di questa fase il vettore risulta diviso 16
17 idealmente in due parti, non necessariamente uguali, quella con tutti gli elementi più piccoli del pivot e quella con tutti gli elementi più grandi del pivot. Quindi si applica il quicksort ricorsivamente a ciascuna delle due parti del vettore. Le chiamate ricorsive terminano quando la porzione di vettore analizzato è di dimensione 1. Supponiamo di avere il seguente vettore: Consideriamo i due estremi del vettore e calcoliamone la media. Nel nostro caso tale media è 15. Chiamiamo tale media pivot. L idea è di mettere nella parte iniziale del vettore tutti gli elementi più piccoli del pivot e nella parte finale gli elementi più grandi del pivot. Per fare questo procediamo come segue: scandiamo il vettore da sinistra a destra, andando a cercare il primo elemento che risulta più grande del pivot. Questo elemento è probabilmente nella posizione sbagliata. Teniamo in memoria la posizione di questo elemento e cominciamo a scandire il vettore da destra a sinistra, andando a cercare il primo elemento più piccolo del pivot. Tale elemento viene scambiato con quello trovato prima, e si prosegue in questo modo fino a quando ogni elemento non sia stato esaminato ed eventualmente trasportato nella metà di pertinenza In particolare nel nostro vettore 23 risulta subito più grande del pivot e 7 minore del pivot. Quindi i due elementi vengono scambiati si passa ad esaminare il secondo elemento, il 14. Essendo minore di 15 non verrà spostato e si passa all elemento successivo. Anche 6 < 15 e si passa al successivo. Si trova 16 > 15, quindi ci si ferma e si comincia ad esaminare gli elementi da destra a sinistra. Si trova subito il 12 < 15 che verrà quindi scambiato col 16. Otteniamo quindi: Andando avanti da sinistra a destra si trova il 34 > 15. Si riparte quindi da destra e si trova il 4 < 15. I due elementi vengono scambiati Quindi gli indici che scandiscono i due vettori si incontrano. A questo punto tutti gli elementi più piccoli del pivot si trovano prima della posizione 5, mentre tutti quelli più grandi si trovano dalla posizione 6 in poi. L algoritmo viene quindi richiamato ricorsivamente su ciascuna delle due parti. 17
18 Si noti che gli elementi che alla fine di una di queste fasi sono collocate in una metà, non dovranno più superare il confine ideale fra le due parti. Quindi un ordinamento indipendente di ciascuna delle due parti porterà ad un ordinamento dell intero vettore. Il codice in Pascal che implementa questo algoritmo è il seguente. procedure quicksort (var V:vettore, left,right:integer); var i,j, pivot:integer; procedure scambia(var x,y:integer); var aux:integer; aux:=x; x:=y; y:=aux; {quicksort} i:=left; j:=right; pivot:=(v[left]+v[right]) div 2; repeat While V[i]<pivot do i:=i+1; While V[j]>pivot do j:=j-1; scambia(v[i], V[j]) i:=i+1; j:=j-1; until i>j; if right<j then quicksort(v,right,j); if i>left then quicksort(v,i,left) Una chiamata della funzione farà un numero di confronti (di ogni elemento col pivot) proporzionale alla taglia della parte di vettore che si sta esaminando. In più ci sono due chiamate ricorsive sulle due parti del vettore. Possiamo notare che se il vettore venisse diviso esattamente a metà la funzione di ricorsione che ne deriverebbe sarebbe la stessa del mergesort. In questo caso particolarmente fortunato avremmo quindi che la complessità dell algoritmo sarebbe O(n log n). Tuttavia il modo in cui il vettore viene suddiviso dipende molto dalla sorte nel senso che dipende dalla scelta del pivot. In casi particolarmente sfortunati, il pivot potrebbe essere tale da creare una partizione sbilanciata del vettore, ossia alla prima chiamata di quicksort il vettore verrebbe diviso in una parte di n 1 elementi e un parte di un solo elemento. Quindi una sola delle due chiamate ricorsive si attiva, ma su un vettore di taglia n 1. La seconda chiamata ricorsiva l algoritmo farà quindi n 1 confronti. Se siamo ancora particolarmente sfortunati il nuovo pivot sbilancia ancora la partizione. Otteniamo dunque un unica chiamata ricorsiva 18
19 su un vettore di taglia n 2. In maniera più formale possiamo dire che se ogni estrazione del pivot ci genera una partizione sbilanciata, la funzione di ricorsione sarà: T (n) = n + T (n 1) = n + (n 1) + T (n 2) = = n + (n 1) + (n 2) = = n(n + 1)/2 ossia O(n 2 ). Dunque abbiamo dimostrato il seguente Teorema Teorema 2.2 Il quicksort ha una complessità nel caso pessimo di O(n 2 ). Ci possiamo chiedere comunque come questo algoritmo lavora in media. Si può dimostrare che nel caso medio questo algoritmo si comporta in maniera più probabile come nel caso migliore. Cioé: Teorema 2.3 La complessità del quicksort nel caso medio è O(n log n). In realtà le costanti celate dietro l ordine di grandezza sono molto piccole. Questo è il motivo per cui il quicksort ha in genere delle performances addirittura migliori del mergesort, che ha una complessità worst case migliore. Notiamo infine che il quicksort è un algoritmo non adattivo in quando la sua esecuzione non dipende da come è fatto l input (può dipendere eventualmente dalla scelta del pivot). Inoltre non è stabile poiché per esempio il primo 16 viene scambiato col e alla fine della prima ricorsione il vettore risulta Si può notare che 16 1 e 16 2 non si scambieranno più di posto prima della fine dell algoritmo. 2.5 Countingsort L algoritmo che ora andiamo a descrivere può essere applicato quando gli elementi che dobbiamo ordinare appartengono ad un insieme finito. Per esempio possiamo supporre che gli elementi da ordinare siano interi compresi in un intervallo finito, oppure le lettere dell alfabeto. Invece l algoritmo non può essere applicato ad un insieme di numeri reali contenuti in un intervallo, perchè in un intervallo sono contenuti infiniti numeri reali. L algoritmo di countingsort funziona come segue. Supponiamo di volere ordinare un vettore V, i cui elementi sono tratti da un insieme finito. 19
20 si definisce un vettore count con taglia uguale alla dimensione dell insieme da cui gli elementi sono tratti. Si inizializzano tutte le caselle del vettore a 0. L elemento i-esimo di tale vettore servirà a contare quante volte l elemento di valore i è presente nel vettore. si scorre il vettore V con un ciclo, e per ogni i si incrementa di 1 la casella V[i] (perchè è stato visto un nuovo elemento con valore V[i]). si considera il vettore count e a partire dal secondo elemento collezioniamo in ogni posizione k tutte le somme parziali dei primi k elementi di count. In questo modo alla fine count[k] indicherà la posizione in cui dovremo inserire l ultimo elemento con valore k nel vettore ordinato. percorrendo il a ritroso vettore V dall ultima posizione alla prima per ogni indice i inseriamo questo elemento in un vettore ausiliario W nella posizione count[v[i]]. Quindi si decrementa count[v[i]] per determinare dove andrà messo il prossimo elemento di valore V[i]. Vediamo come funziona su un esempio. Supponiamo di voler ordinare un vettore di 16 interi nell intervallo [1, 5]. Si considera un vettore count di dimensione 5 e si inizializza a 0 count= Si inizia a scandire il vettore V. Il primo elemento è un 3, dunque si incrementa il contatore count[3] al secondo passo si incrementerà count[1]. quindi di nuovo count[3] count= count= count= e così via. Alla fine della iterazione il vettore count sarà il seguente: count= Costruiamo il vettore delle somme incrementali count=
21 A questo punto consideriamo un vettore W della stessa dimensione di V e cominciamo a scandire V da destra a sinistra. W= count= Al primo passo si legge V[16]=4. Allora questo 4 viene inserito nella posizione count[4] (14) e si decrementa count[4]. W= 4 count= Questo procedimento garantisce che l ultima occorrenza del 4 sia messo nell ultima posizione in cui deve figurare un 4 nel vettore risultante. Applicato ad ogni elemento, questo farà si che il counting sort risulti stabile. Al secondo passo si trova un 3, che si inserisce nella posizione count[3] (11), e si decrementa di uno count[3], che diventa 10. Terzo passo Quarto passo W= 3 4 count= W= count= W= count=
22 Quinto passo W= count= Sesto passo W= count= Settimo passo W= count= Ottavo passo W= count= Nono passo W= count= Decimo passo W= CONT=
23 Undicesimo passo W= CONT= Dodicesimo passo W= CONT= Tredicesimo passo W= CONT= Quattordicesimo passo W= CONT= Quindicesimo passo W= CONT= Sedicesimo passo W= CONT=
24 Il codice che implementa questo algoritmo è il seguente: procedure countingsort (var V:vettore); var i,k:integer; count:array [1..k] of integer; W:vettore for j:=1 to k do {inizializzazione di count} count[j]:=0; for i:=1 to n do {creazione del vettore contatore} count[v[i]]:=count[v[i]]+1; for j:=2 to k do {creazione del vettore delle somme incrementali} count[i]:=count[i]+count[i-1]; for i:=n downto 1 do {Costruzione del vettore ordinato} W[count[V[i]]]:=V[i]; count[v[i]]:=count[v[i]]-1; for i:=i to n do V[i]:=W[i]; {copia del vettore W in V} Questo algoritmo contiene un ciclo di lunghezza k per l inizializzazione di count, un ciclo di lunghezza n per la creazione del vettore count, un ciclo di lunghezza k per la creazione del vettore delle somme incrementali, un ciclo di lunghezza n per la creazione del vettore ordinato e un ciclo di lunghezza n per copiare il vettore ordinato in V. Essendo tutti cicli disgiunti, la complessità dell algoritmo è uguale al massimo tra O(k) e O(n). In genere si suppone che n sia molto maggiore di k, quindi il counting sort ha complessità O(n). Si noti che questo risultato non contraddice il teorema del lower bound per gli algoritmi di sorting. Infatti il counting sort non è un algoritmo di sorting basato su confronti, e questo è possibile perchè sfrutta pesantemente l ipotesi che l insieme da cui sono tratti gli elementi è un insieme finito. Infatti se così non fosse, non saremmo in grado di dimensionare il vettore count. L algoritmo sfrutta un vettore ausiliario (il vettore W), quindi non lavora in loco. Inoltre il funzionamento dell algoritmo non dipende dal vettore iniziale. Quindi è non adattivo. Infine, per come è stato implementato, l algoritmo è stabile. Nella seguente tabella schematizziamo tutte le caratteristiche fondamentali degli algoritmi di sorting illustrati. 24
25 Caso pessimo Caso medio Caso migliore In Loco Adattivo Stabile Selectionsort O(n 2 ) O(n 2 ) O(n 2 ) SI NO NO Bubblesort O(n 2 )? O(n) SI SI SI Mergesort O(n log n) O(n log n) O(n log n) NO NO NO Quicksort O(n 2 ) O(n log n) O(n log n) SI NO NO Countingsort O(n) O(n) O(n) NO NO SI 25
Fondamenti di Informatica. Algoritmi di Ricerca e di Ordinamento
Fondamenti di Informatica Algoritmi di Ricerca e di Ordinamento 1 Ricerca in una sequenza di elementi Data una sequenza di elementi, occorre verificare se un elemento fa parte della sequenza oppure l elemento
Divide et impera. Divide et impera. Divide et impera. Divide et impera
Divide et impera Divide et impera La tecnica detta divide et impera è una strategia generale per impostare algoritmi (par. 9.4). Consideriamo un problema P e sia n la dimensione dei dati, la strategia
Esercizi di Algoritmi e Strutture Dati
Esercizi di Algoritmi e Strutture Dati Moreno Marzolla [email protected] Ultimo aggiornamento: 3 novembre 2010 1 Trova la somma/1 Scrivere un algoritmo che dati in input un array A[1... n] di n interi
Due 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
Tecniche Algoritmiche: divide et impera
Tecniche Algoritmiche: divide et impera Una breve presentazione F. Damiani - Alg. & Lab. 04/05 Divide et impera (o Divide and conquer) Per regnare occorre tenere divisi i nemici e trarne vantaggio F. Damiani
Algoritmi di ordinamento: Array e ricorsione
Laboratorio di Algoritmi e Strutture Dati Aniello Murano http://people.na.infn.it people.na.infn.it/~murano/ 1 Algoritmi di ordinamento: Array e ricorsione 2 1 Indice Algoritmi di ordinamento: Insertion
Algoritmi di ricerca. Per ricerca si intende qui il procedimento di localizzare una particolare informazione in un elenco di dati.
E. Calabrese: Fondamenti di Informatica Algoritmi-1 Algoritmi di ricerca Per ricerca si intende qui il procedimento di localizzare una particolare informazione in un elenco di dati. Per esempio: - cercare
Esercizi vari. Alberto Montresor. 19 Agosto, 2014
Esercizi vari Alberto Montresor 19 Agosto, 2014 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente, è possibile saltare alle rispettive soluzioni
Algoritmi di ordinamento
Algoritmi di ordinamento! Selection Sort! Quick Sort! Lower bound alla complessità degli algoritmi di ordinamento Ordinamento 1 Selection Sort SelectionSort(dati[]) { for (i=0; idati.length-1; i++) { min
Algoritmi e Strutture di Dati (3 a Ed.) String matching. Alan Bertossi, Alberto Montresor
Algoritmi e Strutture di Dati (3 a Ed.) String matching Alan Bertossi, Alberto Montresor STRING MATCHING. Date una stringa P di m caratteri (pattern) e una stringa T di n caratteri, con m n, trovare un
PROVETTE D ESAME. Algoritmi e Strutture Dati
PROVETTE D ESAME Algoritmi e Strutture Dati ESERCIZIO 1 Si ottengano limiti superiori e inferiori per la seguente ricorrenza ESERCIZIO 1 ESERCIZIO 2 Dato un albero binario T, il grado di sbilanciamento
Algoritmi e Strutture Dati. Capitolo 4 Ordinamento
Algoritmi e Strutture Dati Capitolo 4 Ordinamento Ordinamento Dato un insieme S di n oggetti presi da un dominio totalmente ordinato, ordinare S Esempi: ordinare una lista di nomi alfabeticamente, o un
Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base
Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base Dati e Algoritmi I (Pietracaprina): Esercizi 1 Problema 1. Sia T una stringa arbitraria di lunghezza n 1 su un alfabeto Σ. È sempre possibile
Note per la Lezione 4 Ugo Vaccaro
Progettazione di Algoritmi Anno Accademico 2016 2017 Note per la Lezione 4 Ugo Vaccaro Ripasso di nozioni su Alberi Ricordiamo che gli alberi rappresentano una generalizzazione delle liste, nel senso che
Algoritmi 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
Algoritmi 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
Un esempio di calcolo di complessità: insertion sort
Un esempio di calcolo di complessità: insertion sort Vediamo su un esempio come si può calcolare la complessità di un algoritmo... L esempio è un metodo semplice per ordinare arrays: insertion sort, o
Note per la Lezione 6 Ugo Vaccaro
Progettazione di Algoritmi Anno Accademico 2016 2017 Note per la Lezione 6 Ugo Vaccaro Ancora sulla tecnica Programmazione Dinamica Nella lezione scorsa abbiamo appreso che la tecnica Divide-et-Impera,
Albero di Riscorsione
Albero di Riscorsione Albero di ricorsione Un albero di ricorsione è un modo di visualizzare cosa accade in un algoritmo divide et impera L etichetta della radice rappresenta il costo non ricorsivo della
Array e Oggetti. Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 1. Dispensa 12. A. Miola Dicembre 2006
Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 1 Dispensa 12 Array e Oggetti A. Miola Dicembre 2006 http://www.dia.uniroma3.it/~java/fondinf1/ Array e Oggetti 1 Contenuti Array paralleli
Problemi, istanze, soluzioni
lgoritmi e Strutture di Dati II 2 Problemi, istanze, soluzioni Un problema specifica una relazione matematica tra dati di ingresso e dati di uscita. Una istanza di un problema è formata dai dati di un
Introduzione alla programmazione
Introduzione alla programmazione Risolvere un problema Per risolvere un problema si procede innanzitutto all individuazione Delle informazioni, dei dati noti Dei risultati desiderati Il secondo passo consiste
UNIVERSITÀ DEGLI STUDI DI PAVIA FACOLTÀ DI INGEGNERIA. Matlab: esempi ed esercizi
UNIVERSITÀ DEGLI STUDI DI PAVIA FACOLTÀ DI INGEGNERIA Matlab: esempi ed esercizi Sommario e obiettivi Sommario Esempi di implementazioni Matlab di semplici algoritmi Analisi di codici Matlab Obiettivi
Esercizi Capitolo 12 - Divide-et-Impera
Esercizi Capitolo 12 - Divide-et-Impera Alberto Montresor 19 Agosto, 2014 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente, è possibile saltare
Sommario. Ordinamento. Selection Sort Bubble Sort/ Shaker Sort Shell Sort
Ordinamento Sommario Ordinamento Selection Sort Bubble Sort/ Shaker Sort Shell Sort Cosa e' l'ordinamento Il problema consiste nell elaborare insiemi di dati costituiti da record I record hanno sono costituiti
Algoritmi e Strutture Dati
Algoritmi Ricorsivi e Maria Rita Di Berardini, Emanuela Merelli 1 1 Dipartimento di Matematica e Informatica Università di Camerino A.A. 2006/07 I conigli di Fibonacci Ricerca Binaria L isola dei conigli
Appunti di informatica. Lezione 10 anno accademico Mario Verdicchio
Appunti di informatica Lezione 10 anno accademico 2016-2017 Mario Verdicchio Esercizio Scrivere un programma che, data una sequenza di 10 interi (scelta dall utente), la ordini in ordine crescente Soluzione
Algoritmi greedy. Gli algoritmi che risolvono problemi di ottimizzazione devono in genere operare una sequenza di scelte per arrivare alla soluzione
Algoritmi greedy Gli algoritmi che risolvono problemi di ottimizzazione devono in genere operare una sequenza di scelte per arrivare alla soluzione Gli algoritmi greedy sono algoritmi basati sull idea
Un tipico esempio è la definizione del fattoriale n! di un numero n, la cui definizione è la seguente:
Pag 29 4) La ricorsione 4.1 Funzioni matematiche ricorsive Partiamo da un concetto ben noto, quello delle funzioni matematiche ricorsive. Una funzione matematica è detta ricorsiva quando la sua definizione
3.4 Metodo di Branch and Bound
3.4 Metodo di Branch and Bound Consideriamo un generico problema di Ottimizzazione Discreta dove X è la regione ammissibile. (P ) z = max{c(x) : x X} Metodologia generale di enumerazione implicita (Land
Laboratorio di Programmazione Appunti sulla lezione 4: Divide et impera e algoritmi di ordinamento
Laboratorio di Programmazione Appunti sulla lezione 4: Divide et impera e algoritmi di ordinamento Alessandra Raffaetà Università Ca Foscari Venezia Corso di Laurea in Informatica Ricerca binaria Assunzione:
Appunti sui Codici di Reed Muller. Giovanni Barbarino
Appunti sui Codici di Reed Muller Giovanni Barbarino Capitolo 1 Codici di Reed-Muller I codici di Reed-Muller sono codici lineari su F q legati alle valutazioni dei polinomi sullo spazio affine. Per semplicità
Alcune nozioni preliminari di teoria elementare di insiemi e funzioni
Alcune nozioni preliminari di teoria elementare di insiemi e funzioni Alberto Pinto Corso Propedeutico - METS A.A. 2013/2014 1 Insiemi 1.1 Generalità Diamo la definizione di insieme secondo Georg Cantor,
Complementi ed Esercizi di Informatica Teorica II
Complementi ed Esercizi di Informatica Teorica II Vincenzo Bonifaci 21 maggio 2008 4 Problemi di ottimizzazione: il Bin Packing Il problema bin packing è il seguente: dato un insieme di n oggetti di dimensioni
Esercizi Capitolo 10 - Code con priorità e insiemi disgiunti
Esercizi Capitolo 10 - Code con priorità e insiemi disgiunti Alberto Montresor 19 Agosto, 2014 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente,
Ordinamenti per confronto: albero di decisione
Ordinamenti per confronto: albero di decisione Albero di decisione = rappresentazione grafica di tutte le possibili sequenze di confronti eseguite da un algoritmo assegnato di ordinamento per confronto
Algoritmi e loro proprietà. Che cos è un algoritmo? Un esempio di algoritmo
1 Cos è l informatica? L informatica è la scienza della rappresentazione e dell elaborazione dell informazione Algoritmi e loro proprietà Proprietà formali degli Algoritmi Efficienza rispetto al tempo
RISOLUZIONE IN LOGICA PROPOSIZIONALE. Giovanna D Agostino Dipartimento di Matemaica e Informatica, Università di Udine
RISOLUZIONE IN LOGICA PROPOSIZIONALE Giovanna D Agostino Dipartimento di Matemaica e Informatica, Università di Udine 1. Risoluzione Definitione 1.1. Un letterale l è una variabile proposizionale (letterale
Due numeri naturali non nulli a, b tali che MCD(a,b) = 1 si dicono coprimi o relativamente primi.
MASSIMO COMUNE DIVISORE E ALGORITMO DI EUCLIDE L algoritmo di Euclide permette di calcolare il massimo comun divisore tra due numeri, anche se questi sono molto grandi, senza aver bisogno di fattorizzarli
Precorsi di matematica
Precorsi di matematica Francesco Dinuzzo 12 settembre 2005 1 Insiemi Il concetto di base nella matematica moderna è l insieme. Un insieme è una collezione di elementi. Gli elementi di un insieme vengono
STRUTTURE DI CONTROLLO DEL C++
STRUTTURE DI CONTROLLO DEL C++ Le istruzioni if e else Le istruzioni condizionali ci consentono di far eseguire in modo selettivo una singola riga di codice o una serie di righe di codice (che viene detto
osservazione: 1 MCD(m,n) min(m,n) = si provano i numeri compresi tra 1 e min(m,n) conviene iniziare da min(m,n) e scendere verso 1
Esempio: Leggere due interi positivi e calcolarne il massimo comun divisore. MCD(12, 8) = 4 MCD(12, 6) = 6 MCD(12, 7) = 1 Sfruttando direttamente la definizione di MCD osservazione: 1 MCD(m,n) min(m,n)
Matematica. Corso integrato di. per le scienze naturali ed applicate. Materiale integrativo. Paolo Baiti 1 Lorenzo Freddi 1
Corso integrato di Matematica per le scienze naturali ed applicate Materiale integrativo Paolo Baiti 1 Lorenzo Freddi 1 1 Dipartimento di Matematica e Informatica, Università di Udine, via delle Scienze
Introduzione alla programmazione Algoritmi e diagrammi di flusso. Sviluppo del software
Introduzione alla programmazione Algoritmi e diagrammi di flusso F. Corno, A. Lioy, M. Rebaudengo Sviluppo del software problema idea (soluzione) algoritmo (soluzione formale) programma (traduzione dell
A.A CORSO DI ALGEBRA 1. PROFF. P. PIAZZA, E. SPINELLI. SOLUZIONE ESERCIZI FOGLIO 5.
A.A. 2015-2016. CORSO DI ALGEBRA 1. PROFF. P. PIAZZA, E. SPINELLI. SOLUZIONE ESERCIZI FOGLIO 5. Esercizio 5.1. Determinare le ultime tre cifre di n = 13 1625. (Suggerimento. Sfruttare il Teorema di Eulero-Fermat)
Progettazione di algoritmi
Progettazione di algoritmi Discussione dell'esercizio [vincoli] Prima di tutto rappresentiamo il problema con un grafo G: i nodi sono le n lavorazioni L 1, L 2,, L n, e tra due nodi L h, L k c'è un arco
Algoritmi di ordinamento. Sequential-sort, Bubble-sort, Quicksort
Algoritmi di ordinamento Sequential-sort, Bubble-sort, Quicksort Definizione Dato un multi-insieme V={Vn} N-1 n=0 di valori in D, il problema dell ordinamento è trovare una permutazione n(j) degli indici
8. Completamento di uno spazio di misura.
8. Completamento di uno spazio di misura. 8.1. Spazi di misura. Spazi di misura completi. Definizione 8.1.1. (Spazio misurabile). Si chiama spazio misurabile ogni coppia ordinata (Ω, A), dove Ω è un insieme
Fondamenti di Informatica
Fondamenti di Informatica AlgoBuild: Strutture selettive, iterative ed array Prof. Arcangelo Castiglione A.A. 2016/17 AlgoBuild : Strutture iterative e selettive OUTLINE Struttura selettiva Esempi Struttura
Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2
Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2 Dispensa 06 Algoritmi di ordinamento C. Limongelli Febbraio 2008 http://www.dia.uniroma3.it/~java/fondinf2/ Algoritmi di Ordinamento 1
Riassumiamo le proprietà dei numeri reali da noi utilizzate nel corso di Geometria.
Capitolo 2 Campi 2.1 Introduzione Studiamo ora i campi. Essi sono una generalizzazione dell insieme R dei numeri reali con le operazioni di addizione e di moltiplicazione. Nel secondo paragrafo ricordiamo
Algoritmo basato su cancellazione di cicli
Algoritmo basato su cancellazione di cicli Dato un flusso ammissibile iniziale, si costruisce una sequenza di flussi ammissibili di costo decrescente. Ciascun flusso è ottenuto dal precedente flusso ammissibile
Branch-and-bound per KNAPSACK
p. 1/1 Branch-and-bound per KNAPSACK Rispetto allo schema generale visto in precedenza dobbiamo specificare: come si calcola un upper bound su un sottinsieme; come si effettua il branching; come si individuano
1 Se X e Y sono equipotenti, Sym(X) e Sym(Y ) sono isomorfi
In ogni esercizio c è la data del giorno in cui l ho proposto. 1 Se X e Y sono equipotenti, Sym(X) e Sym(Y ) sono isomorfi Se X è un insieme indichiamo con Sym(X) l insieme delle biiezioni X X. Si tratta
5. DIVIDE AND CONQUER I
Divide-et-Impera (Divide and conquer) 5. DIVIDE AND CONQUER I Mergesort e Relazioni di ricorrenza Esempi di progettazione D&I Moltiplicazione di interi Contare inversioni Divide-et-Impera. Definizione
Capitolo 9. Tipi enumerativi, tipi generici e interfacce. c 2005 Pearson Education Italia Capitolo 9-1 / 73
Capitolo 9 Tipi enumerativi, tipi generici e interfacce c 2005 Pearson Education Italia Capitolo 9-1 / 73 Sommario: Tipi enumerativi, tipi generici e interfacce 1 Definizione di tipi enumerativi La classe
Tecniche di Ordinamento dei Vettori
Tecniche di Ordinamento dei Vettori Corso di Laurea Ingegneria Corso B A.A. 2010-2011 1 Contenuto 1) Generalità 2) Metodi a Minimo Ingombro di Memoria 2.1) Ordinamento per selezione ( Selection Sort )
Esercizi Capitolo 6 - Alberi binari di ricerca
Esercizi Capitolo 6 - Alberi binari di ricerca Alberto Montresor 9 Agosto, 204 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente, è possibile
NOTE DI ALGEBRA LINEARE v = a 1 v a n v n, w = b 1 v b n v n
NOTE DI ALGEBRA LINEARE 2- MM 9 NOVEMBRE 2 Combinazioni lineari e generatori Sia K un campo e V uno spazio vettoriale su K Siano v,, v n vettori in V Definizione Un vettore v V si dice combinazione lineare
Il codice di Sarngadeva
Matematica - Musica Il codice di Sarngadeva È oggi riconosciuto da molti (vedi, ad esempio, Knuth [3]) come diverse nozioni combinatorie di base (quali il sistema binario, il triangolo di Tartaglia-Pascal,
Cammini minimi fra tutte le coppie
Capitolo 12 Cammini minimi fra tutte le coppie Consideriamo il problema dei cammini minimi fra tutte le coppie in un grafo G = (V, E, w) orientato, pesato, dove possono essere presenti archi (ma non cicli)
Algoritmi e Strutture Dati - II modulo Soluzioni degli esercizi
Algoritmi e Strutture Dati - II modulo Soluzioni degli esercizi Francesco Pasquale 6 maggio 2015 Esercizio 1. Su una strada rettilinea ci sono n case nelle posizioni 0 c 1 < c 2 < < c n. Bisogna installare
Esercizi di Matematica per la prova di ammissione alla Scuola Galileiana /16
Esercizi di Matematica per la prova di ammissione alla Scuola Galileiana - 015/16 Esercizio 1 Per quali valori n Z \ {0} l espressione è un numero intero positivo? (n + 5)(n + 6) 6n Soluzione. Il problema
Parte III: Algoritmo di Branch-and-Bound
Parte III: Algoritmo di Branch-and-Bound Divide et Impera Sia z * max {c T x : x S} (1) un problema di ottimizzazione combinatoria difficile da risolvere. Domanda: E possibile decomporre il problema (1)
Programmazione dinamica
Programmazione dinamica Violetta Lonati Università degli studi di Milano Dipartimento di Informatica Laboratorio di algoritmi e strutture dati Corso di laurea in Informatica Violetta Lonati Programmazione
A lezione sono stati presentati i seguenti passi per risolvere un problema:
Calcolo delle radici di un polinomio Problema: Dati i coefficienti a,b,c di un polinomio di 2 grado della forma: ax^2 + bx + c = 0, calcolare le radici. A lezione sono stati presentati i seguenti passi
Il tipo astratto coda con priorità: specifiche sintattiche e semantiche. Realizzazioni.
Il tipo astratto coda con priorità: specifiche sintattiche e semantiche. Realizzazioni. Algoritmi e Strutture Dati + Lab A.A. 14/15 Informatica Università degli Studi di Bari Aldo Moro Nicola Di Mauro
Esercizi Capitolo 7 - Hash
Esercizi Capitolo 7 - Hash Alberto Montresor 19 Agosto, 2014 Alcuni degli esercizi che seguono sono associati alle rispettive soluzioni. Se il vostro lettore PDF lo consente, è possibile saltare alle rispettive
Corso di Calcolo Numerico
Corso di Calcolo Numerico Dott.ssa M.C. De Bonis Università degli Studi della Basilicata, Potenza Facoltà di Ingegneria Corso di Laurea in Ingegneria Meccanica Risoluzione di Equazioni Algebriche Le equazioni
4 0 = 4 2 = 4 4 = 4 6 = 0.
Elementi di Algebra e Logica 2008. Esercizi 4. Gruppi, anelli e campi. 1. Determinare la tabella additiva e la tabella moltiplicativa di Z 6. (a) Verificare dalla tabella moltiplicativa di Z 6 che esistono
Algoritmi e Strutture Dati. HeapSort
Algoritmi e Strutture Dati HeapSort Selection Sort: intuizioni L algoritmo Selection-Sort scandisce tutti gli elementi dell array a partire dall ultimo elemento fino all inizio e ad ogni iterazione: Viene
Laboratorio di Python
Problem solving, Ricorsione, Università di Bologna 13 e 15 marzo 2013 Sommario 1 2 3 4 Errore di semantica Esercizio def vocali(s): voc='' for c in s: if c in 'aeiou': voc=voc+c return voc Cerchiamo di
Un polinomio è un espressione algebrica data dalla somma di più monomi.
1 I polinomi 1.1 Terminologia sui polinomi Un polinomio è un espressione algebrica data dalla somma di più monomi. I termini di un polinomio sono i monomi che compaiono come addendi nel polinomio. Il termine
Minimo albero di copertura
apitolo 0 Minimo albero di copertura efinizione 0.. ato un grafo G = (V, E) non orientato e connesso, un albero di copertura di G è un sottoinsieme T E tale che il sottografo (V, T ) è un albero libero.
Algoritmi e Strutture Dati (Mod. B) Algoritmi Greedy (parte I)
Algoritmi e Strutture Dati (Mod. B) Algoritmi Greedy (parte I) Algoritmi greedy Gli algoritmi per problemi di ottimizzazione devono in genere operare una sequenza di scelte per arrivare alla soluzione
