




























































































Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Varie implementazioni di algoritmi di ordinamento come insertion sort, bubble sort, quick find, quick union e descrizioni di strutture dati come grafo non orientato e orientato. Inoltre, sono presenti esempi di lettura e scrittura di file, allocazione dinamica della memoria e manipolazione di matrici.
Tipologia: Sintesi del corso
1 / 139
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!





























































































IV
- I Teoria - 1 Gli Algoritmi - 1.1 Problemi Decisionali - 1.1.1 Problemi trattabili/intrattabili - 1.2 Ricerche su i vettori - 1.2.1 Ricerca lineare - 1.2.2 Ricerca binaria o dicotomica - 1.3 Algoritmi di ordinamento - 1.3.1 Classificazione - 1.3.2 Insertion Sort - 1.3.3 Bubble Sort - 1.3.4 Selection Sort....................................................................................... - 1.3.5 Counting Sort - 1.4 Analisi della complessit`a - 1.4.1 Classificazione degli algoritmi - 1.4.2 Analisi asintotica di capo peggiore - 1.4.3 Notazione asintotica - 1.5 Online Connectivity - 1.5.1 Quick Find......................................................................................... - 1.5.2 Quick Union - 1.6 Matematica discreta: grafi e alberi - 1.6.1 Grafo - 1.6.2 Incidenza e adiacenza - 1.6.3 Grado di un vertice - 1.6.4 Cammini e raggiungibilita` - 1.6.5 Connessione nei grafi non orientati - 1.6.6 Connessione nei grafi orientati - 1.6.7 Grafi densi o sparsi - 1.6.8 Grafo pesato - 1.6.9 Alberi - 1.7 La ricorsione - 1.7.1 Paradigma Divide et Impera - 1.7.2 Analisi di complessit`a di alcuni algoritmi - 1.7.3 Torri di Hanoi, gioco matematico risolto con il dividi et impera - 1.7.4 Backtracking - 1.8 ADT: Heap, code a priorita` - 1.8.1 Procedura di insert - 1.8.2 Procedura di heapify - 1.8.3 Procedura di BuildHeap - 1.8.4 HeapSort - 1.9 ADT: Tabella di simboli (Symbol Table) - 1.9.1 Operazioni di un ADT SystemTable - 1.9.2 Strutture dati di un ADT SystemTable..................................................... - 1.9.3 Ricerca in un ADT SystemTable - 1.10 Alberi binari di ricerca (BST) - 1.10.1 Operazioni in un BST - 1.10.2 Complessit`a in un BST - 1.10.3 Operazioni utili - 1.10.4 Implementazione Il corso `e tenuto dal Prof. Paolo Enrico Camurati, Prof. Giampiero Cabodi e dal Prof. Sergio Nocco.
I laboratori inizieranno nella settimana del 10 ottobre 2011 e sono nelle date:
Squadra 1 Gioved`ı dalle ore 14:30 alle ore 16:
Squadra 2 Gioved`ı dalle ore 16:00 alle ore 15:
Squadra 3 Venerd`ıdalle ore 11:30 alle ore 13:
Squadra 4 Venerd`ı dalle ore 13:00 alle ore 14:
I testi consigliati sono:
L’esame consiste in due parti, scritto e orale. Lo scritto comprender`a una parte teorica ( 12 punti) e una
parte di programmazione ( 18 punti). Durante lo scritto sar`a possibile consultare manuali di C come il
Deitel & Deitel oppure il Kernighan & Ritchie, inoltre, al termine dello scritto bisogna portar copia del
programa per correggerlo e inviarlo corretto al docente responsabile del corso. Il voto dell’esame orale
non faramedia in quanto sara gia` comprensivo della valutazione dello scritto.
Per consulenze non sono previsti degli orari esatti, ma basta mandare una mail e sara` fissato un appun-
tamento.
Esiste un sottoinsieme di NP denominato come NP-Completo , tali che con una serie di trasforma-
zioni si risolvono in modo polinomaile.
Durante il corso si tratteranno solo problemi di classe P.
Vi `e un metodo generale, la ricerca sequenziale/lineare. Tale algoritmo ha un array di dimenzione n , e lo
scansioniamo dall’indice 0 all’indice n − 1.
La ricerca termina in due condizioni:
i ∈ / [ 0 , n − 1 ] (generalmente − 1 ).
caso migliore 1 accesso
successo caso peggiore n accessi Bisogna carattarizzare l’algoritmo con la sua complessita`
caso medio
n
accessi
insuccesso n accessi
2
nel caso peggiore (una stima conservativa).
✞
1 int rice rca S e q u e n zia le ( int v[], int l, int r, int k)
// l = e stre m o s in is tro , r = e stre m o d e stro , k = ch ia ve
3 {
int i= l;
5 w h ile ( i< r & & k != v [ i])
i+ + ;
7 if( i= = r)
re tu rn - 1 ;
9 re tu rn i;
}
✝ ✆ ✠
Listing 1.1: Ricerca lineare
Si puo effettuare solo su array ordinati per una chiave, che deve essere quella sulla quale si effettua la
ricerca.
Si confronta k , l’elemento da cercare, con l’elemento centrale dell’array, se l’elemento concide si termina,
altrimenti se la chiave `e superiore all’elemento centrale si effettua la ricerca dicotomica nel sottovettore
destro, mentre se la chiave `e inferiore all’elemento centrale si effettua la ricerca dicotomica nel sottovettore
sinistro. Si termina nel caso in cui l’eleento viene trovato, o nel caso l’array su cui si effettua la ricerca
contiene solo un elemento e non e l’elemento ricercato. Questo algoritmo divide l problema in meta ad
ogni passo, quindi si deduce che quest’algoritmo `e di tipo logaritmico.
✞
int rice rc a _ b in a ria ( int
2 {
int c;
4 w h ile (c < = b )
{
6 c = ( a + b)/ 2 ;
if( v [ c ]= = k )
8 re tu rn c;
e lse if( v[ c ] < k )
10 a = c + 1 ;
e lse
12 b = c - 1 ;
}
14 re tu rn - 1 ;
}
6
v[], in t l, in t r, int k )
3
1
2
2
3
1
3
1
3
2
3
3
2
2
3
1
3
1
2
1
3
2
2
1
3
1
2
3
✝ ✆ ✠
Listing 1.2: Ricerca binaria
Sono algoritmi che preso un vettore come parametro di input lo ordinano, secondo una determinata
relazione d’ordine. In generale gli elementi che cercheremo di ordinare saranno dei record/strutture di
dati, nei quali dovra` essere definita una chiave di ordinamento e potrebbero essere definiti dei nuovi dati
satellite (non influenti sull’ordinamento).
Gli algoritmi di ordinamento possono essere classificati secondo metodo diversi:
ordinamento interno se i dati da ordinare sono tutti in memoria centrale, ha accesso diretto ai dati
ordinamento esterno si i dati da ordinare sono, anche non tutti, in memoria esterna (memoria di
massa), ha accesso sequenziale ai dati
ordinamento in loco se per l’ordinamento oltre al vettore saranno necessarie una quantita` finita di
memoria che `e indipendente dalla dimensione del vettore
ordinamento non in loco se per l’ordinamento saranno necessarie delle locazioni di memoria e tale
quantitae dipendente dalla dimensione del vettore
ordinamento stabile se in fase di ordinamento se sono presenti piu` elementi con medesima chiave essi
saranno ordinati ma resteranno con lo stesso ordine con cui erano nel vettore
in base alla complessit`a :
2
) sono gli algoritmi di ordinamento piu` semplici, iterativi e basati sul confronto esempio
di algoritmi di questa classe `e Insersion Sort, Selection Sort, Exchange/Bubble Sort
2 ) un esempio di questo tipo e lo ShellSort (non verra considerato nel seguito del corso)
esempio di algoritmi di questa classe `e Merge Sort, Quick Sort e Heap Sort
ipotesi molto restrittive, sono basati sul calcolo
esempio di algoritmi di questa classe `e Counting Sort, Radix Sort, Bin/Bucket Sort
Gli algoritmo di ordinamento con complessit`a O ( n · log( n )) sono gli algoritmi di ordinamento migliori
nel caso in cui sia necessario il confronto, mentre la migliore complessita` si ha con complessita O ( n )
ma sono poco utilizzabili perch`e richiedono delle ipotesi troppo restrittive.
Dimostrazione 1 (Limite inferiore di complessit`a negli algoritmi basati sul confronto) Un al-
goritmo di ordinamento basato sul confronto ha come operazione elementare il confronto tra a i
e a j
, sar`a
necessario quindi decidere se a i
< a j
e a i
≥ a j
.
Se volessi rappresentare le decisioni in modo grafico si avrebbe la realizzazione di un albero delle decisioni
(che `e un albero binario). Se volessi trovare l’ordinamento dei seguenti elementi a 1 , a 2 , a 3 (supponendo
di conoscere le relazioni tra gli elementi) avrei la realizzazione del seguente albero decisionale
E
´
un ordinamento che privilegia la posizionazione corretta veloce dei valori alti.
Come struttura dati di ingresso necessita un vettore.
Tale algoritmo ha un approccio incrementale, pertanto il vettore concettualmente sar`a suddiviso in due
sottovettori:
vettore in ingresso
ordinati, inizialmentee vuotoSi ha la terminazione dell’algoritmo nel caso in cui il sottovettore destro coincide con il vettore di ingresso,
dato ciochee stato fin’ora esplicitato sarebbe necessario effettuare confronti per n − 1 elementi, dove
n e la dimensione del vettore,e possible anche cercare di ottimizzarlo facendo evitare dei controlli se
sono certamente inutili, una buona ottimizzazione si puo` avere aggiungendo un flag che mi indica se ci
sono stati scambi; se alla fine dell’iterazione non sono avvenuti scambi allora significa che il vettore e gia
ordinato e quindi si pu`o terminare precocemente l’ordinamento.
✞
1 v o id b u b b le _ so rt( int A [], in t n )
{
3 int i, j, te m p ;
for( i= 0 ; i< n - 1 ; i+ + )
5 {
for ( j = 0 ; j< n - 1 - i; j+ + )
7 {
if( A [ j] > A [ j+ 1 ])
9 {
11
13
15 }
}
te m p = A [ j];
A [ j] = A [ j+ 1 ];
A [ j + 1 ] = te m p ;
}
}
✝ ✆ ✠
Listing 1.4: BubbleSort
✞
vo id o p t_ b u b b le _ so rt ( in t A [], int n )
2 {
int i, j, te m p , fin e ;
4 fin e = 0 ;
for( i= 0 ; i< n - 1 & &! fin e ; i+ + )
6 {
fin e = 1 ;
8 for ( j = 0 ; j< n - 1 - i; j+ + )
{
10 if( A [ j] > A [ j+ 1 ])
{
12 te m p = A [ j];
A [ j] = A [ j+ 1 ];
14 A [ j + 1 ] = te m p ;
fin e = 0 ;
16 }
}
18 }
}
✝ ✆ ✠
Listing 1.5: BubbleSort ottimizzato con flag
La versione ottimizzata potra dei miglioramenti nel caso medio, ma la complessit`a asintotica di caso
peggiore resta invariata.
n
Analisi asintotica L’algoritmo `e composto da confronti, di costo unitario, e da due cicli:
Pertanto
n
2
T ( n ) = ( n − 1) + ( n − 2) +... + 2 + 1 = = O ( n
2
)
2
Caratteristiche `e un algoritmo di ordinamento stabile e in loco.
L’algoritmo consiste nella ricerca del minimo valore presente nel vettore e posizionarlo nella prima posi-
zione, cercare il secondo minimo e metterlo nella seconda posizione e cos`ıvia, il procedimento va eseguito
n volte se n `e la dimensione del vettore.
Come struttura dati di ingresso necessita un vettore. Tale algoritmo ha un approccio incrementale,
pertanto il vettore concettualmente sar`a suddiviso in due sottovettori:
Si ha la terminazione dell’algoritmo nel caso in cui il sottovettore sinistro coincide con il vettore di
ingresso.
✞
✆ ✠
Analisi asintotica L’algoritmo `e composto da confronti, di costo unitario, e da due cicli:
Pertanto
2 T ( n ) = ( n − 1) + ( n − 2) +...
2
2
Caratteristiche `e un algoritmo di ordinamento stabile e in loco.
E
´
un algoritmo di ordinamento non basato sul confronto ma basato sul calcolo.
Intuitivamente l’algoritmo cerca di determinare il quanti elementi vanno messi prima di un determinato
elemento, pertanto verra` assegnata direttamente all’elemento la posizione corretta (per poter avere alla
fine l’ordinamento).
Tale algoritmo `e molto utile in presenza di chiavi ripetute, in quanto altrimenti si avrebbe un uso eccessivo
della memoria (sarebbe utile anche che le chiavi fossero vicine per evitare che ci sia memoria inutilizzata).
Occorre innanzitutto conoscere l’ampiezza dell’intervallo entro il quale va fatto l’ordinamento, occorre
cio`e conoscere l’elemento minimo e l’elemento massimo.
10
1 vo id se le ctio n _ so rt ( int A [], in t l, int r)
{
3 int i, j, te m p , m in ;
fo r( i= l; i< r; i+ + )
5
{
m in = i;
7
for( j= i+ 1 ; j < = r; j + + )
{
9
if( A [ j] < A [ m in ])
m in = j;
11 }
te m p = A [ i];
13
A [ i] = A [ m in ];
A [ m in ] = te m p ;
15
}
}
✝
Listing 1.6: SelectionSort
4
2
i
1
log n
n
n · log n
n
2
n
3
2
n
costante
logaritmico
lineare
linearitmico
quadratico
cubico
esponenziale
14
16
18
20
22 }
o ut = ( in t ) m a llo c ( size o f( in t) n );
fo r( i= 0 ; i< n ; i+ + )
occ [ A [ i]- m in ]+ + ;
fo r( i= 1 ; i< n ; i+ + )
occ [ i]+ = o cc [i - 1 ];
fo r( i= n - 1 ; i > = 0 ; i--)
o ut [( o cc [ A [ i]]--) - m in ]= A [ i];
re tu rn o ut;
✝ ✆ ✠
Listing 1.7: CountingSort
Nella stesura di un buon algoritmo bisogna anche cercare di prevedere la memoria e il tempo che viene
utilizzato dall’algoritmo.
La previsione del tempo non consiste nell’immaginare il tempo impiegato in secondi, ma giudicare il tempo
necessario proporzionale al numero di passi e/o operazioni che bisogna svolgere. Per tale previsione `e
necessario sapere la dimensione del problema, i dati specifici non sono influenti in quanto si fanno sempre
previsioni conservative.
S ( n ) → spazio occupato in memoria
T ( n ) → tempo di esecuzione
Gli algoritmi si classificano in:
Si effettua una stima del limite superiore di T ( n ). Sarebbe necessario effettuare una stima per dimensioni
molto grandi ( n → +∞), inoltre si sceglie il caso peggiore in quanto non sar`a mai possibile trovare casi
peggiori a quello che `e stato esaminato nell’analisi asintotica (stima conservativa).
Si cerca di avere una complessita minima possibile in quanto un buon algoritmo puo compensare un
hardware poco prestante.
Esempio 1 (Analisi asintotica nella ricerca lineare) Poich`e in una ricerca il caso peggiore si ha
quando non viene trovata la chiave. Poich`e abbiamo esaminato precedentemente tale tipo di ricerca e
si e osservato che si effettuano al massimo n passi, pertanto l’algoritmoe cresce linearmente con la
dimensione dei dati.
Esempio 2 (Analisi asintotica nella ricerca dicotomica) Analisi:
2
a
n
elementi
n
elementi
-...
n
elementi
12
L’algoritmo termina nel caso peggiore se la dimensione del vettore `e di 1 solo elemento.
n
2
i
L’algoritmo ha complessita` logaritmica.
= 1 ⇒ n = 2
i
⇒ i = log 2
n
Esempio 3 (Analisi asintotica dell’ InsersionSort) Il ciclo esterno viene eseguito n − 1 volte. Nel
caso peggiore il ciclo interno scandisce tutto il vettore ordinato (il ciclo `e eseguito al massimo n − 1 volte).
Pertanto
n
T ( n ) = 1 + 2 + 3 +... = i =
i =
n · ( n − 1)
2
E
´
possibile quindi poter affermare che l’InsersionSort abbia complessit`a quadratica.
Vi sono tre notazioni utilizzate, esse esprimono diverse proprieta`.
Deftnizione 1 (Notazione asintotica O ) Si dice che T ( n ) appartiene a O ( g ) si a partire da un certo
valore n 0 in poi g > T ( n ).
∃ c > 0 , ∃ n 0 > 0 / A n ≥ n 0 0 ≤ T ( n ) ≤ c · g ( n )
Deftnizione 2 (Notazione asintotica Ω) Tale notazione implica che esiste un limite inferiore alla
complessita asintotica di caso peggiore, cioconsente di dimostrare se un algoritmoe il migliore o meno.
Se si riesce a dimostrare che un algoritmo ha limite inferiore significa che non puo` esistere un altro
algoritmo con complessit`a migliore.
Se T ( n ) = a m
· n
m
1 · n
m −
1
+... + a 0 ⇒ T ( n ) ∈ Ω( n
m
)
Deftnizione 3 (Notazione asintotica Ω) Si usa tale notazione implica che esiste una funzione che
schiaccia sia sopra che sotto, ovviamente con due coefficienti numerici, e ci da informazioni molto pi`u
accurate sull’andamento esatte di T ( n ).
T ( n ) ∈ Θ ⇒ ∃ c 1 , c 2 > 0 , ∃ n 0 > 0 / A n ≥ n 0 0 ≤ c 1 · g ( n ) ≤ T ( n ) ≤ c 2 · g ( n )
Significa che ricevo in ingresso na coppia di interi ( p, q ), p e q rappresentano i nodi mentre ( p, q ) rappre-
senta la connessione tra p e q (filo di connessione).
La relazione e commutativa, cioe se p e connesso con _q_ allora anche _q_e connesso con p , ed `e anche
transitiva, cioe se _p_e connesso con q e q e connesso con _t_ allora _p_e connesso con t.
Si avr`a in output la lista delle connessioni incognite in precedenza.
Si avrauna struttura di dati a grafo, che conterra i nodi e gli archi (rappresentano nel caso specifico la
connessione).
Le relazioni di connessione possono rappresentare:
Immaginiamo di avere una rete con 10 nodi numerati da 0 a 9, con degli archi che rappresentano le
connessioni tra due nodi.
Implicitamente il verso non si esprime, realizzando cos`ı un arco bidirezionale.
Si cerca di evitare l’uso di tutte le connessioni non necessarie (cioe gia note in precedenza).
L’ipotesi fondamentale `e che non esiste una struttura dati esistente (e completa a priori), ma di volta in
volta che si aggiunge un collegamento si aggiorna la struttura (l’OnlineConnectivity realizza la struttura
al volo).
Bisognera` istituire due operazioni astrette:
ftnd trova l’insieme a cui appartiene l’oggetto
union unisce due insiemi distinti