Estratto del documento

01.ALGORITMI E CLASSI DI PROBLEMI

Algoritmo: sequenza finita di istruzioni per risolvere un problema.

Tipologie di Problemi:

• Decisione: nei quali la risposta è binaria (si o no).

o Decidibili: esiste algoritmo risolutivo.

▪ Trattabili: risolvibili in tempo ragionevole. Allora esiste un algoritmo polinomiale in

grado di risolvere questa sottocategoria di problemi (tesi di Edmonds-Cook-Karp).

Questi problemi si dicono di classe P.

▪ Intrattabili: non risolvibili in tempo ragionevole. [Torri di Hanoi per n elevato].

Solitamente in questa categoria ricadono quelli di classe NP.

o Indecidibili: non esiste algoritmo risolutivo. [congettura di Goldbach]

• Ricerca: nei quali si cerca la soluzione valida tra le n soluzioni possibili [n=0,1,…infinito].

• Verifica: nei quali si stabilisce se la risposta data sia valida.

• Ottimizzazione: nei quali si cerca la soluzione migliore ad un dato problema.

Classi di Problemi:

• P: sono problemi Polinomiali.

• NP: sono problemi Non-deterministico Polinomiali, ovvero

quelli per i quali non si può escludere che vi sia una

soluzione polinomiale anche se non si sia ancora trovata.

• NP-Completo: sono problemi costruiti in modo tale che

ogni altro problema NP sia riducibile ad esso attraverso

trasformazioni polinomiali.

• NP-Hard: un problema è di questa classe se ogni problema

NP è riducibile ad esso in tempo polinomiale.

02.ANALISI DI COMPLESSITA DEGLI ALGORITMI

Analisi di Complessità: indipendentemente dalla macchina e dalla tipologia o contenuto dei dati, è la

previsione delle risorse richieste dall’algoritmo per la sua esecuzione, tramite metodi empirici e analitici.

Classificazione degli Algoritmi:

• : costante.

• (): logaritmico.

• : lineare.

• (): linearitmico.

: quadratico.

: cubico.

: esponenziale.

Analisi Asintotica di Caso Peggiore: si fa allo scopo di avere una stima per un limite superiore all’algoritmo

() su n dati nel caso peggiore (algoritmo compie il numero massimo di passi possibile per la risoluzione).

→ ∞,

Si dice asintotica perché si stima la complessità per in quanto per n piccoli la complessità è irrilevante

Notazione asintotica O:

() = (()) ↔ ∃ > 0, ∃ > 0 → ∀ > ≤ () ≤ ()

0 0

In parole povere, g(n) è limite superiore lasco dell’algoritmo T(n) se,

superata la soglia , T(n) non supera mai g(n) moltiplicata per una

0

costante. [Come simbolo di Landau di analisi 1].

Notazione asintotica Ω:

() = (()) ↔ ∃ > 0, ∃ > 0 → ∀ > ≤ () ≤ ()

0 0

In questo caso l’algoritmo non sarà mai di complessità minore di g(n),

perché questa, moltiplicata per una costante, sarà il suo limite inferiore

lasco. Sempre oltre un certo numero di dati .

0

Notazione asintotica Θ:

() = (()) ↔ ∃ , > 0, ∃ > 0 → ∀ >

1 2 0 0

≤ () ≤ () ≤ ()

Questo sta a voler dire che g(n) è sia limite superiore che inferiore e

quindi la complessità dell’algoritmo ha lo stesso andamento di g(n).

Problema della Connettività (Algoritmi Union-Find):

Tra i numerosi problemi di programmazione che esistono, quello della connettività si ripropone in diverse

forme ed è bene conoscerlo: il problema consiste nell’acquisizione di istruzioni in forma “p-q”, che indicano

che l’oggetto p è connesso con l’oggetto q, e allora controllare che la coppia sia già connessa, in caso

negativo stabilire la nuova connessione, altrimenti procedere con la nuova coppia. Per grandi quantità di dati

questi controlli sarebbero impossibili senza algoritmi efficienti.

È bene definire 3 proprietà di connessione fondamentali: 1. Riflessiva: p è connesso con sé stesso. 2.

Simmetrica: se p è connesso a q, allora q è connesso a p. 3. Transitiva: se p è connesso con q e q è connesso

con r, allora p è connesso con r.

Per i problemi di connettività si adoperano 2 operazioni fondamentali: la union sostituisce i 2 insiemi che

contengono 2 oggetti con l’unione dei due insiemi, la find trova l’insieme che contiene un dato oggetto.

SI

Input della FIND: elementi nello Prossima

coppia p-q stesso insieme? coppia

UNION: unione degli

NO insiemi che li contengono

E dato questo problema l’ottimizzazione non è solo l’algoritmo, ma anche l’organizzazione del dato. Infatti

consideriamo un approccio dove non vengono memorizzate tutte le connessioni. Vediamo gli algoritmi di

Quick-find e Quick-union.

Quick-find: questo algoritmo prevede un vettore di n elementi, dove n corrisponde al numero di nodi da

connettere. L’indice di ogni casella di questo vettore corrisponde all’i-esimo nodo. Il vettore è inizializzato

come v[i]=i. Ogni nuova connessione p-q ricevuta in input implica la sostituzione su ogni nodo di p con q (o

viceversa). [se rileggi e non capisci vai a pagina 12 di Sedgewick].

Quick-union: questo algoritmo prevede che ogni nodo abbia un puntatore a suo “padre” o a sé stesso. Quindi

per sapere se 2 nodi sono connessi bisogna risalire attraverso i puntatori di entrambi finché non si trova la

radice di entrambi (nodo che punta sé stesso). Se esiste i 2 elementi sono connessi, altrimenti si fa puntare

uno dei 2 all’altro. -> Quick-union pesata: aggiungendo un controllo e facendo puntare l’albero più piccolo a

quello più grande si abbatte la complessità.

Complessità di QF, QU, WQU:

• QF: per ognuna delle operazioni (M) di union, iteriamo un ciclo for per N volte. QF(N)=O(M*N) =O(N).

In questo caso la (quick) find ha costo unitario e la complessità dipende dalla union.

• QU: nel peggiore dei casi abbiamo N-1 puntatori e nel migliore 1 solo, quindi mediamente N/2

invocazioni di find. Dunque QU(N) = O(M*N/2) = O(N). Qui la (quick) union ha costo unitario.

2

WQU: in questo caso la distanza massima di un nodo dalla radice in un albero da nodi è n, e se 2

+1

2 2

alberi da nodi si uniscono, si genererebbe un albero da nodi nel quale la distanza massima

tra nodo e radice è n+1. Si dimostra (probabilmente con l’approssimazione di Stirling) che WQU(N) =

O(2*log(N)) = O(log(N)). La union ha costo unitario.

03.ALGORITMI DI ORDINAMENTO

Classificazione degli algoritmi di ordinamento:

• Ord. Interno: su dati in memoria centrale ai quali si ha accesso diretto.

o In loco/non in loco: l’ordinamento si dice “in loco” quando oltre agli n dati da ordinare si ha

un numero fisso di locazioni di memoria ausiliarie. “non in loco” se le locazioni ausiliarie

dipendono dal numero di dati da ordinare.

o Stabili/instabili: l’ordinamento si dice “stabile” se rimane invariato l’ordinamento relativo

dei dati se si cambia la chiave di ordinamento. “instabile” se non viene mantenuto questo

ordine, poi si capisce attraverso gli esempi.

• Ord. Esterno: su dati in memoria di massa ai quali si ha accesso sequenziale (non li tratteremo).

Limite inferiore degli algoritmi basati sul confronto: se ogni confronto ha un costo unitario, costruiamo un

albero binario la cui altezza è h ed è pari al numero di dati da ordinare. Dunque le foglie (quindi soluzioni)

2

sono esattamente , che per l’approssimazione di Stirling, possiamo paragonare in questo modo:

2 ≥ ! > ( ) , → ℎ > ln ( ) = ln − ln = Ω( ln )

Scan Lineare: uno scan lineare è una ricerca su un array di un determinato dato. Intuitivamente compie al

più N (numero di dati) controlli. Quindi ha complessità O(N).

Algoritmi di ordinamento e relative complessità: [Sedgewick da p228]

//per ognuno dei successivi codici, definiamo qualche macro

#define less(A, B) (A<B) //ritorna un valore booleano

#define scambio(A, B) { int t = A; A = B; B = t; } //scambio di A con B

#define scambioCondizionale(A, B) if(less(B, A)) scambio(A, B)

Bubble Sort: questo ordinamento consiste nell’attraversare il file, scambiando se necessario gli elementi

adiacenti (all’indietro) finché non è più necessario scambiare elementi. L’ordinamento è in loco perché sono

richiesti solo gli indici come variabili ausiliarie e stabile perché si mantiene l’ordine relativo tra elementi

uguali: se un elemento è uguale all’altro questi non si scambiano ma quello a sinistra “continua il cammino

di quello che è arrivato da destra”.

void bubbleSort(int a[],int l, int r) // l = estremo inferiore, r = estremo superiore

{int i,j;

for(i = l; i < r; i++)

for(j = r; j > i; l--)

scambioCondizionale(a[j-1],a[j]);

}

La complessità dell’algoritmo si ricava considerando che si tratta di 2 cicli annidati, quello esterno che è

eseguito n-1 volte e quello interno che è eseguito n-i-1 volte. Il numero di scambi è dello stesso ordine di

grandezza del numero di confronti, questi si ricavano con la sommatoria di Gauss:

( + 1)

( ( ()

() = − 1) + − 2) + ⋯ + 2 + 1 = ∑( − ) = = 2

=1

Essendo il numero di confronti e il numero di scambi dello stesso ordine questo ci dice che la complessità del

2

() = ( ).

Bubble Sort è

Selection Sort: questo ordinamento consiste nel sostituire al primo elemento dell’array il dato più piccolo

dello stesso, poi cerca il secondo elemento più piccolo e lo sostituisce al secondo e così via. È un tipo di

ordinamento in loco perché usa solo una variabile di supporto e instabile perché non mantiene l’ordine

relativo tra elementi che corrispondono in funzione della chiave.

void selectionSort(int a[], int l, int r) // l = estremo inferiore, r = estremo superiore

{int i, j;

for(i = l; i < r; i++)

{int min = i;

for(j = i + 1; j <= r; j++)

if( less(a[j], a[min])) min = j;

scambio(a[j], a[min]));

}

}

La complessità dell’algoritmo si ricava considerando che si tratta di 2 cicli annidati, quello esterno che è

eseguito n-1 volte e quello interno che è eseguito n-i-1 volte. Gli scambi sono al più n, quindi per la

complessità non ci interessa, ma per ogni iterazione del ciclo interno viene effettuato un confronto, la

complessità è data dal numero di confronti, e il numero di confronti si ricava con la sommatoria di Gauss:

( + 1)

( ( ()

() = − 1) + − 2) + ⋯ + 2 + 1 = ∑( − ) = = 2

=1 2

() = ( ).

Questo ci dice che la complessità del Selection Sort è

Insertion Sort: Questo è il metodo che si usa comunemente per ordinare le carte nella propria mano. Durante

il procedimento gli elementi a sinistra sono ordinati tra loro ma è possibile che un elemento sulla destra

venga messo tra gli elementi a sinistra (il fatto che non venga turbato l’ordine relativo lo rende un algoritmo

stabile)

void insertionSort(int a[],int l,int r)// l = estremo inferiore, r = estremo superiore

{int i,j,v;

//mettiamo subito l'elemento più piccolo nella prima cella

for(i = r; i > l; i--) scambioCondizionale(a[i-1],a[i]);

for(i = l+2; i <= r; i++)

{j=i; v=a[i];

while(less(v,a[j-1]))

//v non potrà mai essere più piccolo di a[0]

//quindi non serve il controllo j>1

{a[j]=a[j-1]; j--;}

//finchè v è più piccolo dell'elemento

//a sinistra viene fatto spazio

a[j]=v;

}

} 2

() = ( ).

L’algoritmo è chiaramente in loco e, sempre per gli stessi motivi, la sua complessità è

Shell Sort: lo Shell Sort è un caso particolare dell’Insertion Sort perché di fondo è lo stesso algoritmo che però

punta ad ordinare dei sotto vettori del vettore principale che sono costruiti col criterio di essere a distanza h

uno dall’altro. Ad ogni ciclo esterno il valore di h diventa più piccolo fino ad arrivare ad 1. L’algoritmo, sc

Anteprima
Vedrai una selezione di 6 pagine su 23
Appunti Corso Algoritmi e Programmazione Pag. 1 Appunti Corso Algoritmi e Programmazione Pag. 2
Anteprima di 6 pagg. su 23.
Scarica il documento per vederlo tutto.
Appunti Corso Algoritmi e Programmazione Pag. 6
Anteprima di 6 pagg. su 23.
Scarica il documento per vederlo tutto.
Appunti Corso Algoritmi e Programmazione Pag. 11
Anteprima di 6 pagg. su 23.
Scarica il documento per vederlo tutto.
Appunti Corso Algoritmi e Programmazione Pag. 16
Anteprima di 6 pagg. su 23.
Scarica il documento per vederlo tutto.
Appunti Corso Algoritmi e Programmazione Pag. 21
1 su 23
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher vale78420 di informazioni apprese con la frequenza delle lezioni di Algoritmi e programmazione avanzata e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Politecnico di Torino o del prof Cabodi Giampiero.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community