Docente:
Giuseppe Scollo
Università di Catania
Facoltà di Scienze Matematiche, Fisiche e Naturali
Corso di Laurea in Informatica, I livello, AA 2009-10
consideriamo l'algoritmo di ricerca di un nome in un elenco proposto in una lezione precedente
riguardo alla dipendenza dal valore dell'input, dobbiamo considerare due casi
se l'elenco ha N nomi, la ricerca sequenziale esamina mediamente :
la ricerca sequenziale esamina N elementi nel caso peggiore, in qualsiasi esito
assunto: dipendenza delle prestazioni dell'algoritmo da un parametro primario N
(uno solo, per semplicità e senza perdita di generalità)
il tempo di esecuzione ("costo" più significativo degli algoritmi nella maggior parte dei casi) tipicamente cresce come una delle seguenti funzioni di N, e la rispettiva crescita si dice:
nell'esempio precedente, non c'è alternativa alla ricerca sequenziale se l'elenco non è ordinato
se l'elenco dei nomi è ordinato (in un qualsiasi ordinamento totale), la prestazione media della ricerca sequenziale può migliorare nel caso di esito negativo, arrestando l'esecuzione del ciclo quando l'elemento confrontato con il nome dato è maggiore di questo (se l'ordine è ascendente)
se l'elenco è ordinato, si può fare (molto) meglio!
l'idea dell'algoritmo di ricerca binaria è la seguente:
la ricerca binaria, ad ogni passo con esito negativo dimezza la dimensione dello spazio di ricerca nel passo successivo
il guadagno di efficienza rispetto alla ricerca sequenziale è esponenziale!
come nel caso dell'algoritmo di quick-union pesata, il guadagno di efficienza è dovuto all'operare lungo un cammino, in questo caso da radice a foglia, di un albero bilanciato, di altezza logaritmica rispetto al numero dei nodi
a mo' di esempio, l'albero in figura rappresenta le opzioni disponibili alla ricerca binaria di un numero nell'elenco ordinato dei numeri da 1 a 15, ed il cammino in rilievo mostra le scelte fatte per la ricerca di 3
albero di ricerca binaria dei numeri da 1 a 15
definizione: funzione inversa dell'esponenziale
ovvero, logb x è l'esponente da dare a b per ottenere x :
=
x
=
x
dalla definizione discendono le proprietà:
=
1 / loga
b
=
logb
x +
logb
y ,
logb
(x /y)
=
logb
x -
logb
y
notazione per basi speciali:
=
loge
x
=
log2
x
un'applicazione delle approssimazioni intere del logaritmo binario:
⌊
lg
N⌋
+1
=
⌈
lg(N+1)⌉
bit
le prestazioni della ricerca binaria si devono all'ipotesi che lo spazio di ricerca sia ordinato
un metodo semplice può usare come primitiva una vecchia conoscenza: una funzione di ricerca del massimo in un insieme, per la quale già disponiamo di un algoritmo
nel nostro caso occorre però un algoritmo un po' diverso, perché vogliamo ordinare una sequenza data, non necessariamente di numeri, e ci serve una funzione che ci dia la posizione (ad es., della prima occorrenza) del massimo elemento trovato nella sequenza
tali adattamenti sono proposti come esercizi, assieme ad altri raffinamenti del seguente algoritmo di
ordinamento, in cui A =
A1 ... AN è la sequenza data, e dove
indichiamo con il termine procedura
un algoritmo che può modificare i dati che riceve in ingresso
possiamo ora rispondere alla domanda posta all'inizio della pagina precedente, con riferimento all'algoritmo appena visto, ragionando come segue:
sorgono spontanee due domande:
rispondiamo nell'ordine:
che vuol dire esattamente che una funzione è approssimazione asintotica di un'altra?
la notazione O grande designa una limitazione asintotica della velocità di crescita:
def. :
g(N) è O(f(N))
se esistono costanti c e
N0
tali che
N > N0
⇒
g(N) < cf(N)
utilità della notazione O grande:
discendono direttamente dalla definizione molte proprietà della notazione O grande che permettono spesso di manipolarne le espressioni "come se la O non ci fosse", ad esempio:
=
O(1)
e
kO(f(N)) =
O(kf(N)) =
O(f(N)),
per ogni costante k,
=
O(f(N)+g(N)),
O(f(N))O(g(N)) =
O(f(N)g(N))
la limitazione asintotica espressa dalla notazione O grande non è sufficiente a caratterizzare la velocità di crescita
la notazione ≈
(letta "all'incirca")
designa l'approssimazione asintotica
di una funzione con un'altra:
def. :
f(N) ≈
g(N)
se f(N) =
g(N)+h(N)
e h(N)/g(N) → 0 per
N →
∞
per caratterizzare solo la velocità di crescita l'approssimazione asintotica chiede troppo... basta invece il seguente concetto
la notazione ∝
(letta "proporzionale a")
designa la proporzionalità asintotica
di una funzione ad un'altra:
def. :
f(N) ∝
g(N)
se esiste una costante c tale che
f(N) ≈
cg(N)
finora si sono considerate stime e analisi delle prestazioni di algoritmi per un dato problema, o classe di problemi, e per essi risulta utile distinguere fra
per complessità computazionale di un problema si intende:
il costo computazionale nel caso peggiore di un algoritmo per un dato problema costituisce un limite superiore alla complessità computazionale del problema:
è anche utile determinare limiti inferiori alla complessità computazionale di problemi, analizzandone caratteristiche inerenti, ma questo compito è di solito più difficile