Prefix tree (také bore [1] , ray [2] , loadovaný strom [3] , anglicky trie [4] ) je datová struktura , která umožňuje uložit asociativní pole , jehož klíče jsou řetězce. Je to zakořeněný strom , jehož každá hrana je označena nějakým symbolem, takže pro jakýkoli uzel jsou všechny hrany spojující tento uzel s jeho syny označeny různými symboly. Jsou vybrány některé uzly stromu prefixů (na obrázku jsou podepsány čísly) a má se za to, že strom prefixů obsahuje daný řetězec-klíč tehdy a jen tehdy, pokud lze tento řetězec číst na cestě od kořene k nějaké ( jediný pro tento řetězec) vybraný uzel. V některých aplikacích je vhodné považovat všechny uzly stromu za vybrané.
Na rozdíl od binárních vyhledávacích stromů tedy klíč, který identifikuje konkrétní uzel ve stromu, není explicitně uložen v tomto uzlu, ale je dán pozicí tohoto uzlu ve stromu. Klíč získáte vypsáním znaků v řadě, které označují hrany na cestě od kořene k uzlu. Kořenový klíč stromu je prázdný řetězec. Vyhrazené uzly často ukládají dodatečné informace spojené s klíčem a obvykle jsou vyhrazeny pouze listy a možná některé interní uzly.
Ve stromu předpon jsou tři hlavní operace: kontrola, zda klíč ve stromu existuje, odstranění klíče ze stromu a vložení nového klíče (možná s dalšími souvisejícími informacemi). Každá z těchto operací je implementována sestupem stromu z kořene, ale účinnost takové operace přímo závisí na organizaci navigace přes uzly. Pro následnou analýzu různých přístupů k tomuto problému si označme délku řetězce, který je požadován/mazán/vkládán, a označme velikost abecedy , tedy počet různých znaků na okrajích daného stromu prefixů. . Nechť má tento uzel syny (s ). Označte odkazy na tyto syny a symboly, které označují hrany spojující s odpovídajícími syny.
Zvažte strom předpon obsahující všechny přípony řetězce délky . Tento strom má alespoň uzlů a zabírá tak paměť. V tomto příkladu je tato nehospodárná spotřeba paměti způsobena velkým počtem uzlů pouze s jedním potomkem. Pro boj s tímto problémem vyvinul Donald Morrison [5] modifikaci stromu prefixů, nazvanou komprimovaný strom prefixů (existují také možnosti kompaktní strom předpon, základní strom , stlačený otvor , kompaktní otvor , stlačený nosník , stlačený zatížený strom ; Morrison sám [5] nazval jeho strukturu "strom PATRICIA" a tento název se stále někdy vyskytuje).
Komprimovaný strom prefixů obsahující dané řetězce je minimální strom z hlediska počtu uzlů, jehož každá hrana je označena neprázdným řetězcem (a nikoli symbolem, jako v běžném stromu prefixů), takže jakýkoli řetězec může být načten na cestě od kořene k některému (vybranému) uzlu a pro jakýkoli uzel jsou první znaky na všech štítcích na okrajích podřízeného uzlu různé. Například komprimovaný strom předpon zobrazený na obrázku obsahuje osm slov ruského jazyka a pouze listy jsou v něm vybrané uzly.
Komprimovaný strom prefixů se získá z běžného stromu prefixů obsahujícího klíče postupným mazáním každého uzlu (kromě kořene), který má pouze jednoho syna a není vybrán, zatímco otec a syn mazaného uzlu jsou spojeni a výsledná hrana je označené řetězcem získaným spojením štítků na hranách nadřazeného uzlu a uzlového syna (ačkoli tato metoda vytváření komprimovaného stromu prefixů se nedoporučuje[ kým? ] ).
Efektivita komprimovaného stromu prefixů vychází ze způsobu, jakým jsou reprezentovány popisky hran. Protože každý štítek je podřetězcem nějakého řetězce , lze jej reprezentovat pomocí trojice čísel , kde (zde označuje podřetězec řetězce začínající na pozici a končící na pozici ). Pokud jsou všechny řetězce podřetězci jednoho daného řetězce , pak mohou být štítky reprezentovány dvojicemi čísel odpovídajících podřetězcům . Navigace v uzlech je organizována stejným způsobem jako v obvyklém stromu prefixů, ale první znaky v popiscích na hranách uzlu-son slouží jako referenční znaky: například v komprimovaném stromu prefixů na obrázku uzel odpovídající k řetězci "west" má tři syny a referenční symboly v tomto uzlu jsou "i", "n", "b", což jsou první znaky ve štítcích "ib", "nick", "b" na okraje uzlu-son. Lze ukázat, že komprimovaný strom prefixů pro sadu řetězců nemá celkem více než uzlů a zabírá tedy paměť, kromě paměti potřebné k uložení samotných řetězců .
Operace dotazování, mazání a vkládání na komprimovaném stromu předpon lze provádět stejným způsobem jako na běžném stromu předpon sestupem z kořene. V tomto případě se algoritmus poněkud zkomplikuje kvůli nutnosti číst obsah štítku z odpovídajícího podřetězce jednoho z řetězců při sestupu podél okrajů označených řetězci o délce dva nebo více . Teoreticky lze dobu běhu takového algoritmu odhadnout stejným způsobem jako u běžného stromu prefixů (tedy jako , , v závislosti na organizaci navigace v uzlech), ale v praxi se často operace na komprimovaném stromu prefixů se ukázaly být rychlejší díky skutečnosti, že většina cesty z kořene do uzlu vede podél okrajů a není potřeba často odkazovat na datové struktury v uzlech.
Pokud jsou délky všech řádků relativně malé (například v rámci délky jednoho řádku mezipaměti , což je u mnoha moderních procesorů 64 bajtů), lze se vyhnout chybám mezipaměti způsobeným častými skoky mezi různými štítky pomocí jiné metody sestupu stromu ( právě tato metoda byla popsána v Morrisonově článku [5] ). Zvažte například algoritmus pro nalezení nejdelšího prefixu daného řetězce , který lze číst na cestě od kořene k některému uzlu v daném komprimovaném stromu prefixů; ostatní operace mohou být implementovány analogicky.
Algoritmus spočívá v prvním průchodu dotazem pouze na uzly stromu, přeskočením hran, a tak sestupem co nejníže ve stromu najít řetězec z množiny , který má nejdelší společnou předponu s řetězcem . Poté musíte vypočítat společnou předponu a obvyklý naivní algoritmus a vrátit výsledek. V níže uvedeném pseudokódu podobném C znamená s[i] řetězec , kořen kořen stromu a každý uzel x obsahuje následující pole/metody: x->len je délka štítku na okraji od x k otci x; x->child(c) je odkaz na potomka uzlu x spojeného s x hranou se štítkem začínajícím na c, nebo nullptr, pokud takový syn neexistuje; x->src je takové číslo, že řetězec na cestě od kořene k x je předponou řetězce .
size_t find_longest_prefix ( string t ) { struct node_t * x = root ; for ( size_t i = 0 ; i < t . length (); i += x -> len ) if ( x -> dítě ( t [ i ]) != nullptr ) x = x -> dítě ( t [ i ]); jinak zlomit ; návratová délka společné předpony t a s [ x -> src ]; }Struktura je široce používána ve vyhledávacích algoritmech a dalších aplikacích.
Strom (datová struktura) | |
---|---|
Binární stromy | |
Samovyrovnávací binární stromy |
|
B-stromy |
|
předponové stromy |
|
Binární dělení prostoru | |
Nebinární stromy |
|
Rozbití prostoru |
|
Jiné stromy |
|
Algoritmy |
|
Struny | |
---|---|
Míry podobnosti řetězců | |
Hledání podřetězců | |
palindromy | |
Sekvenční zarovnání | |
Struktury přípon | |
jiný |