Boyerův–Mooreův algoritmusBoyerův–Mooreův algoritmus pro vyhledávání řetězců je v matematické informatice efektivní algoritmus pro vyhledávání v textu, který je standardním benchmarkem v literatuře o praktickém vyhledávání řetězců.[1] Algoritmus vytvořil Robert S. Boyer a J Strother Moore v roce 1977.[2] Původní článek obsahoval statické tabulky pro výpočet posunutí vzorku bez vysvětlení, jak je získat. Algoritmus pro vytváření tabulek byl publikován v navazujícím článku; ten obsahoval chyby, které v roce 1980 opravil Wojciech Rytter.[3][4] Algoritmus předzpracovává vzorek, jehož výskyt se má vyhledávat. Je tedy vhodný v případech, kdy vzorek je mnohem kratší než text nebo když se stejný vzorek používá ve více hledáních. Boyerův–Mooreův algoritmus používá informace získané během předzpracování pro přeskakování částí textu, díky čemuž je násobně rychlejší než mnoho jiných algoritmů vyhledávání vzorků. Algoritmus obecně pracuje rychleji pro větší délku vzorku. Jeho klíčovou vlastností je, že vzorek porovnává od konce místo od začátku, a že místo porovnávání každého jednotlivého znaku v textu přeskakuje kusy textu o více znaků. Definice
Zarovnání vzorku PAN k textu ANPANMAN, od k=3 do k=8. Shoda se objevuje na pozici k=5.
PopisBoyerův–Mooreův algoritmus hledá výskyty vzorku P v textu T explicitním porovnáváním znaků v různých pozicích. Místo zkoušení všech zarovnání (kterých je ) Boyerův–Mooreův algoritmus používá informace získané předzpracováním P, aby bylo možné co nejvíc zarovnání přeskočit. Starší algoritmy vyhledání kontrolují, zda se každý znak textu neshoduje s prvním znakem vzorku. Pokud je nalezena shoda v prvním znaku, kontrolují se následující znaky textu s dalšími znaky vzorku. Pokud není nalezena úplná shoda, pak je text opět kontrolován znak po znaku ve snaze najít shodu. Musí být tedy prověřen téměř každý znak textu. Základním principem tohoto algoritmu je, že se začátek vzorku přiloží na začátek textu (jinak řečeno konec vzorku se zarovná s indexem m textu) a porovná se poslední znak vzorku s příslušným znakem textu; pokud znaky nesouhlasí, pak není nutné prohledávat další znaky ve vzorku. Naopak, pokud se znak z textu ve vzorku vůbec nevyskytuje, je možné vzorek posunout o celou jeho délku m; pokud se vyskytuje, je možné posunout vzorek tak, aby znak v textu byl zarovnaný s jedním z výskytů téhož znaku ve vzorku. Toto skákání po textu místo kontroly každého znaku v textu snižuje počet porovnání, které bylo třeba provést, což je klíčem k efektivitě algoritmu. Formálněji algoritmus začíná se zarovnáním , kdy je začátek P je zarovnaný se začátkem T. Znaky v P a T se pak porovnávají počínaje indexem m v P a k v T. Řetězce se porovnávají pozpátku od konce P k začátku P. Porovnání pokračuje, dokud není dosažen začátek P (což znamená, že byla nalezena úplná shoda) nebo dokud se neobjeví neshoda; pak je vzorek posunut dopředu (vpravo) podle maximální hodnoty povolené několika pravidly. Porovnání se provádí znovu v novém zarovnání, a proces se opakuje, dokud vzorek není posunut za konec T, což znamená, že další shoda již neexistuje. Pravidla pro posun jsou realizována vyhledáváním v tabulce v konstantním čase; tabulka se vytvoří během předzpracování vzorku P. Posunová pravidlaPosun se určí aplikací dvou pravidel: pravidla pravidlo špatného znaku a pravidla dobré přípony. Skutečné posunutí je maximum posunutí určených těmito pravidly. Pravidlo špatného znakuPopis
Ukázka pravidla špatného znaku se vzorkem P = NNAAMAN. Ve sloupci označeném X je neshoda – ve vstupním textu je N, zatímco ve vzorku je A. Vzorek je posunut doprava (v tomto případě o 2), takže je nalezen další výskyt znaku N (ve vzorku P) vlevo od aktuálního znaku (kterým je prostřední A). Pravidlo špatného znaku se týká znaku v T, který se neshoduje se znakem v P. Pokud se najde další výskyt tohoto znaku vlevo v P, zkusí se posun který tento výskyt uvede do souladu s chybným výskytem v T. Pokud se neshodující se znak vlevo v P nevyskytuje, zkusí se posun, který posune celé P za místo neshody. PředzpracováníPředzpracování závisí na přesném tvaru, jaký má mít tabulka pro pravidlo špatného znaku, ale jednoduché řešení vyhledávání v konstantním čase je následující: vytvořit dvojrozměrnou tabulku, jejíž jeden index je index znaku c v abecedě a druhý index i ve vzorku. Hodnotou bude výskyt c v P s následujícím indexem , nebo -1, pokud žádný takový výskyt neexistuje. Navržený posun pak bude , s časovou složitostí vyhledávání a prostorovou složitostí , kde k je počet symbolů abecedy. Implementace v jazyce C a Javě níže mají prostorovou složitost (make_delta1, makeCharTable). To je totéž jako původní delta1 a BMH tabulka špatného znaku. Tato tabulka převádí znak na pozici na posunutí o velikosti , přičemž přednost má poslední výskyt s nejmenším posunutím. Všechny nepoužité znaky jsou nastaveny na , což je hodnota plnící roli zarážky. Pravidlo dobré příponyPopis
Ukázka pravidla dobré přípony se vzorkem P = ANAMPNAM. t je v tomto případě T[6..8] a t' je P[2..4]. Myšlenka i implementace pravidla dobré přípony je mnohem složitější než pravidlo špatného znaku. Stejně jako pravidlo špatného znaku také využívá toho, že algoritmus začíná porovnávat na konci vzorku a postupuje směrem k začátku vzorku. To lze popsat takto:[5]
PředzpracováníPravidlo dobré přípony vyžaduje dvě tabulky: jednu pro použití v obecném případě (když je kopie t' nalezena), a druhou pro použití, když obecný případ nevrátí smysluplný výsledek. Tyto tabulky budeme označovat L a H. Jejich definice jsou následující:[5]
Obě tyto tabulky lze sestrojit v čase a zabírají prostor . Posun zarovnání pro index i v P popisuje vztah nebo . H se použije pouze tehdy, když je nulové nebo byla nalezena shoda. Galilovo pravidloJednoduchou ale významnou optimalizaci Boyerova-Mooreova algoritmu zveřejnil v roce 1979 Zvi Galil.[6] Galilovo pravidlo se nezabývá posouváním, ale zrychlením skutečného porovnávání při každém zarovnání tím, že přeskakuje úseky, o nichž je známo, že se shodují. Předpokládejme, že při zarovnání k1 je vzorek P porovnán s T až po znak c v T. Pak, pokud se P posune na k2, tak, že jeho levý konec je mezi c a k1, musí se v další fázi porovnání předpona P shodovat s podřetězcem T[(k2 - n)..k1]. Pokud tedy porovnání dojde až na pozici k1 v textu T, lze výskyt P zaznamenat bez explicitního porovnávání za k1. Kromě zvýšení efektivity Boyerova-Mooreova algoritmu, je Galilovo pravidlo požadováno pro důkaz, že algoritmus pracuje v lineárním čase i v nejhorším případě. Galilovo pravidlo je ve své původní verzi účinné pouze pro verze, jejichž výstupem je více shod. Rozsah podřetězců aktualizuje pouze pro c = 0, tj. při plné shodě. Zobecněná verze pro popis dílčích shod byla publikována v roce 1985 jako Apostolicův–Giancarlův algoritmus.[7] VariantyBoyerův–Mooreův–Horspoolův algoritmus je zjednodušením Boyerova–Mooreova algoritmu s použitím pouze pravidla špatného znaku. Apostolicův–Giancarlův algoritmus urychluje proces kontroly, zda při daném zarovnání došlo ke shodě, tím, že vynechává explicitní porovnání znaků. Využívá informace získané během předzpracování vzorku ve spojení s délkami shod přípon zaznamenaných v každém pokusu o shodu. Ukládání délek shod přípon vyžaduje další tabulku stejné velikosti k text je searched. Raitův algoritmus vylepšuje výkonnost Boyerova–Mooreova–Horspoolova algoritmu. Vyhledávací vzorek určitého podřetězce v daném řetězci je odlišný od Boyerova–Mooreova–Horspoolova algoritmu. OdkazyReferenceV tomto článku byl použit překlad textu z článku Boyer–Moore string-search algorithm na anglické Wikipedii.
Literatura
Externí odkazy
|
Portal di Ensiklopedia Dunia