Algoritmi, Strutture Dati e Programmi : Searching (parte 1) Prof. Alberto Postiglione AA 2007-2008 Ricerca di un'informazione in una tabella Determinare se una parola X è presente in un dizionario (cioè in una lista di parole). La parola X può essere il nome di una persona, il titolo di un libro, il numero di una carta di credito, o altro. Supponiamo che N differenti parole siano immagazzinate in N celle di memoria contigue all interno di un elaboratore. Si deve costruire un algoritmo che prenda in input la parola X e dia in output la posizione J in cui appare X. Pertanto, se X è presente l'uscita sarà un numero compreso tra 1 ed N; se invece X non si trova in memoria il risultato sarà 0. Il problema è equivalente a quello della ricerca di una parola in un dizionario. # 2 1
ALGORITMO DI RICERCA SEQUENZIALE Dispense, cap. 5.1 Collocare le N parole nelle celle di memoria da 1 ad N Esaminare a turno ogni parola, a partire dall ultima, tornando indietro verso la prima. Se X si trova nella cella J l algoritmo fornisce in uscita J per poi fermarsi Se vengono esaurite tutte le N possibilità senza alcun esito, si ferma con 0 in uscita. # 4 2
# 5 Alla fine la variabile J conterrà la posizione di Parola nell array Dizionario oppure 0 in caso di assenza. La variabile K non fa parte della computazione, ma serve per poter determinare se il corpo del ciclo va eseguito o se bisogna uscire da esso in caso di presenza di Parola nel vettore Dizionario. Infatti si esce dal ciclo se J=0 (non c è Parola in Dizionario) oppure se K=0 L algoritmo funziona sempre, anche per n=0. # 6 3
Vediamo, adesso, il programma Pascal corrispondente (legge il valore n da input - in questo esempio, per semplicità, n 30 - e poi legge n linee dal file di testo DIZ.TXT, ognuna contenente una parola ) # 7 program ricerca_sequenziale; var Dizionario: array [1..30] of string; Parola : string; N, i,j,k : integer; DIZ : Text; Begin Readln (N); assign (Diz, 'c:\esami\diz.txt'); reset (Diz); for i:=1 to 30 do readln (Diz, Dizionario[i]); close (Diz); read (Parola); J := N; K := 1; while (K<>0) AND (J<>0) do begin if Parola = Dizionario[J] end; writeln (J) end. then K := 0 else J:=J-1; # 8 4
Tale algoritmo risolve sicuramente il problema ma la soluzione non sembra molto efficiente. Infatti, quando il numero di parole diventa grande (ad es. 1.000.000) la ricerca sequenziale richiede, nel caso peggiore, un numero di passi computazionali molto elevato (1.000.000 per il nostro esempio). Tale algoritmo equivale alla ricerca di un numero telefonico fatta consultando l elenco degli abbonati pagina per pagina a partire dalla prima pagina, colonna per colonna, una riga alla volta. # 9 ALGORITMO DI RICERCA BINARIA Dispense, cap. 5.2 5
Su un archivio ordinato è possibile utilizzare una tecnica di ricerca ottimale, la Ricerca Binaria, L ordinamento comporta un vantaggio sostanziale perché in ogni punto dell'elenco è sufficiente un semplice sguardo per eliminare una grande quantità di elementi La Ricerca Binaria permette di cercare un elemento in un archivio con un numero di operazioni pari al logaritmo in base 2 del numero degli elementi presenti nell archivio. # 11 ALGORITMO DI RICERCA BINARIA Si controlla l elemento centrale del dizionario. Se esso è proprio la parola cercata, ci si ferma. In caso contrario, se il dato da cercare segue l elemento centrale si ripete la ricerca nella parte di archivio a destra di quello centrale, scartando tutti i dati contenuti nella semi tabella di sinistra (che precedono sicuramente quello cercato). se il dato da cercare precede l elemento centrale si ripete la ricerca nella parte di archivio a sinistra di quello centrale, scartando tutti i dati contenuti nella semi tabella di destra (che precedono sicuramente quello cercato). Ad ogni passo si dimezza la dimensione dell archivio. # 12 6
Situazione iniziale schedario # 13 Ogni volta elimino la metà delle schede, oppure mi fermo perché ho trovato la scheda cercata Ogni volta divido il numero N delle schede per 2, mi fermo quando N è diventato 1 o 0 Al più eseguo x passi dove x è il logaritmo in base 2 di N Scheda cercata! # 14 7
Innanzitutto dobbiamo stabilire cosa fare quando la tabella contiene un numero pari di elementi. Infatti in questo caso non c è un (unico) elemento centrale. L elemento centrale verrà calcolato come: (sin+des)/2 Le parentesi significano arrotonda per difetto all intero più vicino. Ad es. se sin=1 e des=10, allora (sin+des)/2 = 11/2 = 5,5 = 5 E poi dobbiamo stabilire qual è la condizione di terminazione in caso di insuccesso. L elemento non è nella tabella quando l intervallo diventa vuoto, cioè il limite destro cade più a sinistra del limite sinistro # 15 (parte 1) # 16 8
(parte 2) # 17 program ricerca_binaria; var Dizionario : array [1..30] of string; Parola : string; N,i,J,K : integer; sin, des : integer; DIZ : Text; # 18 begin readln (N); assign (Diz, 'c:\esami\diz.txt'); reset (Diz); for i:=1 to N do readln (Diz,Dizionario[i]); close (Diz); read (Parola); sin := 1; des := n; J := (sin+des) div 2; K := 1; while (K<>0) AND (des>= sin) do begin if Parola = Dizionario[J] then K := 0 else begin if Parola < Dizionario[J] then des := j-1 else sin := J+1; J := (sin+des) div 2; end; end; if k <> 0 then writeln ('Nome assente') else writeln ('Nome in posiz.',j); end. 9