Ricerca dicotomica

algoritmo di ricerca
(Reindirizzamento da Ricerca binaria)

In informatica, la ricerca dicotomica (o ricerca binaria)[1] è un algoritmo di ricerca che individua l'indice di un determinato valore presente in un insieme ordinato di dati. La ricerca dicotomica richiede un accesso casuale ai dati in cui cercare.

Ricerca dicotomica
Esempio: ricerca dell'elemento 4 in una collezione ordinata di nove elementi.
ClasseAlgoritmo di ricerca
Struttura datiArray
Caso peggiore temporalmente
Caso ottimo temporalmente
Caso medio temporalmente
Caso peggiore spazialmente
OttimaleSi

Costo della ricerca

modifica

L'algoritmo cerca un elemento all'interno di un array che deve necessariamente essere ordinato in ordine crescente, effettuando mediamente meno confronti rispetto a una ricerca sequenziale, e quindi più rapidamente rispetto a essa perché, sfruttando l'ordinamento, dimezza l'intervallo di ricerca a ogni passaggio.

La ricerca binaria non usa mai più di   (logaritmo in base 2 di   approssimato per eccesso) confronti per una search hit o una search miss. Tuttavia, a meno che non si controllino ad ogni iterazione i valori dei due indici estremi, la ricerca binaria impiega effettivamente sempre lo stesso tempo su uno stesso array per cercare elementi anche in posizioni diverse; la ricerca sequenziale invece passa da   come caso peggiore a   nel caso medio, fino a   se l'elemento si trova in prima posizione. (cfr. O-grande)

Analisi dell'algoritmo

modifica

L'algoritmo è simile al metodo usato per poter ricevere ambo i lati, ovvero trovare una parola sul dizionario: sapendo che il vocabolario è ordinato alfabeticamente, l'idea è quella di iniziare la ricerca non dal primo elemento, ma da quello centrale, cioè a metà del dizionario. Si confronta questo elemento con quello cercato:

  • se corrisponde, la ricerca termina indicando che l'elemento è stato trovato;
  • se è superiore, la ricerca viene ripetuta sugli elementi precedenti (ovvero sulla prima metà del dizionario), scartando quelli successivi;
  • se invece è inferiore, la ricerca viene ripetuta sugli elementi successivi (ovvero sulla seconda metà del dizionario), scartando quelli precedenti.

Se si arriva al punto che tutti gli elementi vengono scartati, la ricerca termina indicando che il valore non è stato trovato. Una curiosità: l'algoritmo trova applicazione anche per realizzare un programma che indovina un numero naturale (casuale o scelto dall'utente) compreso in un intervallo. Infatti si può ricondurre tale situazione alla ricerca di un elemento su un insieme ordinato che ha, come dati, tutti i numeri naturali compresi nell'intervallo.

Pseudocodice

modifica

Ecco due versioni dell'algoritmo: la versione iterativa e la versione ricorsiva.

  indica il vettore in cui effettuare la ricerca,   e   indicano, rispettivamente, l'estremo inferiore e superiore,   l'indice medio (arrotondato inferiormente) e   indica il valore da ricercare (in questo esempio un intero).

Entrambe le funzioni ritornano l'indice in cui si trova il valore (se trovato) oppure -1 per indicare che non è stato trovato.

Algoritmo iterativo

modifica

Dove   è un array di interi,   indica la posizione del primo elemento dell'array,   indica la posizione dell'ultimo elemento dell'array e   è l'elemento che sto cercando.

function binarySearchIterativo(array A, int p, int r, int v)
    if v < A[p] or v > A[r]
      return -1   -- vuol dire che v non è presente in A
    while p <= r
      q=(p+r)/2
      if A[q] == v
        return q
      if A[q] > v
        r = q-1
      else
        p = q+1
     return -1

Algoritmo ricorsivo

modifica
function binarySearchRicorsivo(array A, int p, int r, int v)
    if (p > r)
    {
      return -1;
    } 
    if (v < A[p] or v > A[r])
    {
      return -1;
    }
    q= (p+r)/2
    if (A[q] == v)
    {
      return q
    }
    else if (A[q] > v)
    {
      return binarySearchRicorsivo(A,p,q-1,v);
    }
    else
    {
      return binarySearchRicorsivo(A,q+1,r,v);
    }

Implementazioni

modifica

Segue un'implementazione, sempre in linguaggio C, dello stesso algoritmo. Qui non viene utilizzata la ricorsività perciò la funzione risulta più efficiente.

// lista[]: lista dei valori interi in cui cercare
// n: valore intero contatore di elementi della lista
// x: valore intero da ricercare
 int ricercaBinariaNonRicorsiva(int lista[], int n, int x)
 {
    int p, u, m;
    p = 0;
    u = n - 1;
    if(x < lista[p] || x > lista[u] ) return -1;
    while(p <= u) {
        m = (p + u) / 2;
        if(lista[m] == x) 
            return m; // valore x trovato alla posizione m
        if(lista[m] < x)
            p = m + 1;
        else
            u = m - 1;
    }
    // se il programma arriva a questo punto vuol dire che 
    // il valore x non è presente in lista, ma se ci fosse
    // dovrebbe trovarsi alla posizione p (nota che qui p > u)
    return -1;
 }

Parametri della funzione: lista è l'array di interi sul quale vogliamo condurre la ricerca,   è il numero degli elementi presenti nell'array e   è il valore da cercare. Durante l'esecuzione le variabili   e  , che puntano inizialmente agli elementi estremi dell'array, si avvicinano progressivamente restringendo sempre più la zona dove si suppone che sia presente il valore cercato  .

Ed ecco un'implementazione ricorsiva in Java:

public class BinarySearch {
	public int binarySearch (int[] a, int p, int r, int k) {
		int q, s = -1;
		if (p <= r) {
			q = (p+r)/2;
			if (k < a[q])
				s = binarySearch(a, p, q-1, k);
			else if (k > a[q])
				s = binarySearch(a, q+1, r, k);
			else if (k == a[q])
				return q;
		}
			return s;
	}
}

dove il metodo binarySearch della classe BinarySearch accetta in ingresso ovviamente un array, due indici cardine e l'elemento da ricercare.

Segue un'implementazione dell'algoritmo molto simile alle precedenti ma in un differente linguaggio, C#.

Ecco un'implementazione senza ricorsione.

/* Funzione per Ricerca Binaria senza ricorsione
int[] array: lista dei valori interi in cui cercare
elemento: numero intero da ricercare */
 int Binary_Search(int[] array, int elemento)  
 {
     int start = 0, end = array.Length - 1, centro = 0;
     while (start <= end)
     {
         centro = (start + end) / 2;
         if (elemento < array[centro])
         {
             end = centro - 1;
         }
         else
         {
             if (elemento > array[centro])
                 start = centro + 1;
             else
                 return centro; // Caso: elemento==array[centro]
         }
     }
     return -1;
 }

Con ricorsione linguaggio C#:

/* Funzione per Ricerca Binaria con ricorsione
int[] arr: array dei valori interi in cui cercare
n: valore intero da ricercare
start, end: valori indice interi (zero-based) di inizio e fine ricerca nell'array
*/
 int RecBinarySearch(int[] arr, int n, int start, int end)
 {
     // Verifica consistenza dei valori di input
     // Eliminabile per ottimizzare esecuzione se il controllo
     // viene fatto prima della chiamata della funzione
     if (start > end || start < 0 || end < 0)
         return -1;
     int middle = (start + end) / 2;
     if (n < arr[middle]) 
        return RecBinarySearch(arr, n, start, middle - 1);
     if (n > arr[middle]) 
        return RecBinarySearch(arr, n, middle + 1, end);
     else
        return middle;
 }
  1. ^ ricerca dicotomica - Treccani, su treccani.it. URL consultato il 17 marzo 2024.

Voci correlate

modifica

Altri progetti

modifica

Collegamenti esterni

modifica
  Portale Informatica: accedi alle voci di Wikipedia che trattano di informatica