



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
Due algoritmi fondamentali in informatica: la ricerca sequenziale e la ricerca binaria. Viene illustrata la logica di funzionamento di entrambi gli algoritmi, analizzando la loro complessità computazionale e il loro comportamento in diversi casi. Esempi pratici e spiega come la ricerca binaria, grazie alla sua efficienza, è particolarmente utile per la ricerca di elementi in sequenze ordinate.
Tipologia: Dispense
1 / 5
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!




Nell’informatica esistono alcuni problemi particolarmente rilevanti, poiché essi:
Uno di questi problemi è la ricerca di un elemento in un insieme di dati (ad es. numeri, cognomi, ecc.).
Iniziamo a definire un po’ più formalmente tale problema definendone l’input e l’output:
Un primo semplice algoritmo che viene in mente è ispezionare uno alla volta gli elementi del vettore, confrontarli con v e alla fine restituire il risultato. Ci si interrompe appena si trova v :
Funzione Ricerca (A: vettore; v: intero)
i 1 while ((i ≤ n) and (A[i] ≠ v)) i i + 1 if (i ≤ n) return i else return null
Oppure:
Funzione Ricerca (A: vettore; v: intero)
i 1 for (i = 1 to n) if (A[i] = v) return i return null
Questo algoritmo ha una complessità di Ө (n) nel caso peggiore (quando, cioè, v non è contenuto nel vettore) e di Ө (1) nel caso migliore (quando v viene incontrato per primo), quindi non abbiamo trovato una stima della complessità che sia valida per tutti i casi. In queste
situazioni diremo che la complessità computazionale dell’algoritmo (in generale, non nel caso peggiore) è un O(n) , per evidenziare il fatto che ci sono input in cui questo valore viene raggiunto, ma ci sono anche input in cui la complessità è minore.
Nei casi, come questo, in cui non sia possibile determinare un valore stretto per la complessità computazionale, ed in cui il caso migliore e quello peggiore si discostano, è naturale domandarsi quale sia la complessità dell’algoritmo nel caso medio.
Supponiamo che v possa apparire con uguale probabilità in qualunque posizione, ossia che
P(v si trova in i-esima posizione) =
Allora il numero medio di iterazioni del ciclo è dato da:
Un metodo alternativo è il seguente. Supponiamo che tutte le possibili n! permutazioni della sequenza di n numeri siano equiprobabili. Di queste, ve ne saranno un certo numero nelle quali v appare in prima posizione, un certo numero nelle quali v appare in seconda posizione, ecc.
Il numero medio di iterazioni del ciclo sarà di conseguenza:
numero medio di iterazioni =
Ora, il numero di permutazioni nelle quali v appare nella i -esima posizione è uguale al numero delle permutazioni di (n-1) elementi, dato che fissiamo solo la posizione di uno degli n elementi, cioè (n – 1)!. Quindi:
numero di iterazioni = = =
Con un metodo diverso abbiamo trovato lo stesso risultato. Dunque, la complessità del caso medio è un Ө(n).
E’ possibile progettare un algoritmo più efficiente nel caso in cui la sequenza degli elementi sia ordinata (come sono, ad esempio, i cognomi degli abbonati nell’elenco telefonico).
Come cerchiamo un nome nell’elenco telefonico? Iniziamo sempre e comunque dalla prima lettera dell’alfabeto? Ovviamente no… andiamo direttamente a una pagina dove pensiamo di trovare cognomi che iniziano con la lettera giusta; se siamo precisi troviamo il nome nella pagina, altrimenti ci spostiamo in avanti o indietro (di un congruo numero di pagine) a seconda che la lettera del cognome che cerchiamo venga prima o, rispettivamente, dopo quelle delle iniziali dei cognomi contenuti nella pagina.
Domandiamoci ora quante siano le posizioni raggiungibili alla i -esima iterazione:
In generale, l’algoritmo di ricerca binaria esegue i iterazioni se e solo se v si trova in una delle 2 i-1^ posizioni raggiungibili con tale numero di iterazioni.
Chiamando n(i) il numero delle posizioni raggiungibili con i iterazioni, possiamo scrivere che il numero medio di iterazioni è:
numero medio di iterazioni = =
Ma ricordando che: = (k-1) 2 k^ + 1
otteniamo:
Ossia, il numero medio di iterazioni si discosta per meno di un confronto dal numero massimo di iterazioni!
Infine, consideriamo una nuova formulazione dell’algoritmo di ricerca binaria (nella quale sono volutamente tralasciati i dettagli per catturarne l’essenza):
Ricerca_binaria (A, v)
se il vettore è vuoto restituisci null ispeziona l’elemento A[centrale] se esso e’ uguale a v restituisci il suo indice se v < A[centrale] esegui Ricerca_binaria (metà sinistra di A, v) se v > A[centrale] esegui Ricerca_binaria (metà destra di A, v)
L’aspetto cruciale di questa formulazione risiede nel fatto che l’algoritmo risolve il problema “riapplicando” se stesso su un sottoproblema (una delle due metà del vettore).
Questa tecnica si chiama ricorsione , ed è un argomento importantissimo che sarà illustrato nel prossimo capitolo.