Algoritmo di Boyer-MooreIn informatica, l'algoritmo di Boyer-Moore è un algoritmo di confronto fra stringhe efficiente che rappresenta il principale punto di riferimento nel suo ambiente.[1] È stato sviluppato da Robert S. Boyer e J Strother Moore nel 1977.[2] L'algoritmo preprocessa la stringa da cercare (il pattern), ma non la stringa esaminata (il testo). È quindi particolarmente adatto per applicazioni in cui il pattern è molto più breve del testo o persiste su più ricerche. L'algoritmo di Boyer–Moore utilizza informazioni raccolte durante la fase di preprocessamento per poter saltare sezioni del testo, risultando in un fattore costante più basso rispetto a molti altri algoritmi su stringhe. In generale, l'algoritmo è eseguito più velocemente con l'aumentare della lunghezza del pattern. La caratteristica fondamentale dell'algoritmo è il confronto in coda del pattern piuttosto che in testa, e la possibilità di muoversi lungo il testo saltando interi gruppi di caratteri piuttosto che verificare ogni singolo carattere presente nel testo. DescrizioneDefinizioni
CaratteristicheL'algoritmo di Boyer–Moore cerca occorrenze di in eseguendo un confronto diretto dei caratteri per diversi allineamenti. Invece di utilizzare un metodo forza bruta per la ricerca di tutti gli allineamenti (che sono in numero ), Boyer–Moore sfrutta le informazioni raccolte preprocessando per saltare più allineamenti possibile. Prima dell'introduzione di tale algoritmo, il tipico metodo per cercare qualcosa all'interno di un testo era esaminare ogni carattere del testo con il carattere iniziale del pattern. Una volta trovato un riscontro si procedeva con un confronto tra i successivi caratteri del testo con il resto del pattern. Se non si verificava un'occorrenza si continuava a controllare il testo carattere per carattere nel tentativo di ottenere un altro riscontro. In questo modo bisognava esaminare quasi ogni carattere del testo. L'intuizione fondamentale in questo algoritmo è che se si confronta la fine del pattern con il testo allora possono essere compiuti dei salti all'interno del testo piuttosto che confrontare ogni singolo carattere. Il motivo è che allineando il pattern al testo, l'ultimo carattere del pattern viene confrontato col carattere nel testo. Se i caratteri non corrispondono non c'è bisogno di effettuare confronti con i caratteri precedenti. Se il carattere nel testo non corrisponde ad alcun carattere del pattern, allora il prossimo carattere del testo da confrontare si trova a n caratteri di distanza lungo il testo, dove n è la lunghezza del pattern. Se il carattere nel testo è presente nel pattern, allora viene compiuto uno spostamento parziale lungo il testo per allineare i caratteri corrispondenti, dopodiché viene ripetuto l'intero processo. Lo scorrimento a salti lungo il testo per effettuare confronti piuttosto che controllare ogni singolo carattere riduce il numero di confronti da compiere, che è la chiave per l'aumento dell'efficienza dell'algoritmo. Più formalmente, l'algoritmo incomincia con un allineamento , cioè l'inizio di corrisponde all'inizio di . I caratteri in e vengono confrontati a partire dalla posizione in e in , e spostandosi all'indietro: le stringhe vengono verificate dalla fine di all'inizio di . Il confronto continua finché non viene raggiunto l'inizio di (significa che si è verificata un'occorrenza) o si ha un mismatch che genera uno spostamento a destra dell'allineamento del massimo valore consentito da alcune regole. I confronti vengono nuovamente eseguiti col nuovo allineamento, e il processo si ripete finché l'allineamento non viene allineato oltre la fine di , che significa che non verranno trovate altre corrispondenze. Le regole di spostamento sono implementate come ricerche su tabelle in tempo costante, utilizzando tabelle generate nel preprocessamento di . Regole di spostamentoUno spostamento viene calcolato applicando entrambe le seguenti regole: la regola del "carattere errato" e la regola del "buon suffisso". L'attuale offset di spostamento è il massimo degli spostamenti calcolati da queste regole. Regola del carattere erratoDescrizione
La regola del carattere errato prende in considerazione il carattere in per cui il processo di confronto è fallito (ipotizzando che tale fallimento si sia verificato). Viene trovata la successiva occorrenza di tale carattere in verso sinistra, e viene proposto uno spostamento tale che porti quella occorrenza in linea con la relativa occorrenza in . Se il carattere in che ha causato il mismatch non presenta occorrenze in verso sinistra, viene allora suggerito uno spostamento che porti interamente oltre la posizione in cui il confronto era fallito. PreprocessamentoI metodi variano riguardo l'esatta forma che dovrebbe assumere la tabella per la regola del carattere errato, ma una semplice soluzione per una ricerca a tempo costante è la seguente: si crea una tabella bidimensionale che viene indicizzata prima con l'indice del carattere nell'alfabeto e poi con l'indice nel pattern. Questa ricerca restituirà l'occorrenza di in con il successivo più alto indice oppure se non esiste tale occorrenza. Lo spostamento proposto sarà allora , con tempo di ricerca e spazio, assumendo un alfabeto finito di dimensione k. Regola del buon suffissoDescrizione
La regola del buon suffisso è decisamente più complessa sia come concetto che come implementazione rispetto alla regola del cattivo carattere. È il motivo per cui i confronti avvengono alla fine del pattern e non all'inizio, ed è formalmente indicato così:[3]
PreprocessamentoLa regola del buon suffisso richiede due tabelle: una da usare nel caso generale, e un'altra da usare o quando il caso generale non restituisce risultati utili o avviene una corrispondenza. Indichiamo queste tabelle rispettivamente con e , e le definiamo come segue:[3]
Entrambe le tabelle sono costruibili in tempo e utilizzano spazio . Lo spostamento di allineamento per l’indice in è dato da oppure . dovrebbe essere usato soltanto se è zero o se si è verificata una corrispondenza. Regola di GalilUna semplice ma importante ottimizzazione del Boyer–Moore fu avanzata da Galil nel 1979.[4] In contrasto con lo spostamento, la regola di Galil si occupa di accelerare i confronti effettivamente compiuti per ogni allineamento saltando quelle sezioni che si sa che corrisponderanno. Supponiamo che per un allineamento , venga confrontato con fino al carattere di . Allora se viene spostato in un tale che la sua estremità sinistra sia compresa tra e , nella prossima fase di confronto un prefisso di deve corrispondere alla sottostringa . Così se i confronti arrivano fino alla posizione di , un'occorrenza di può essere individuata senza effettuare espressamente confronti dopo . Oltre ad aumentare l'efficienza del Boyer–Moore, la regola di Galil è necessaria per dimostrare l'esecuzione a tempo lineare nel caso peggiore. PrestazioniL'algoritmo di Boyer–Moore per com'è stato presentato nel documento originale ha nel caso peggiore un tempo di esecuzione solo se il pattern non appare all'interno del testo. Questo venne dimostrato per la prima volta da Knuth, Morris, e Pratt nel 1977,[5] seguiti da Guibas e Odlyzko nel 1980[6] con un upper bound di di confronti nel caso peggiore. Richard Cole riuscì a fornire una dimostrazione con un upper bound di di confronti nel caso peggiore nel 1991.[7] Quando il pattern è presente all'interno del testo, il tempo di esecuzione dell'algoritmo originale è nel caso peggiore. Questo si nota facilmente quando sia il pattern che il testo consistono unicamente dello stesso carattere ripetuto. Tuttavia, l'inclusione della regola di Galil risulta in tempo di esecuzione lineare in tutti i casi. Note
Voci correlateAltri progetti
Collegamenti esterni
|