トップQs
タイムライン
チャット
視点
接尾辞木
ウィキペディアから
Remove ads
接尾辞木(せつびじき)またはサフィックス木(英: Suffix tree)は、与えられた文字列の接尾部を木構造(基数木)で表すデータ構造であり、多くの文字列操作の高速な実装に利用されている。

BANANA
に $
を補った接尾辞木。根から葉(四角で表示)への6つの経路が6つの接尾辞 A$
, NA$
, ANA$
, NANA$
, ANANA$
, BANANA$
に対応。四角の中の数字は対応する接尾辞の開始位置を示す。接尾辞リンクは破線の矢印で示されている。文字列 の接尾辞木は木構造であり、その枝には文字列が対応し、木構造の根から葉までの経路ごとにそれぞれ の接尾部の1つが対応している。従って、これは の接尾部に関する基数木である。
文字列 からそのような木構造を構築するには、 の長さに対して線形な時間と空間を要する。構築できれば、いくつかの操作が高速化される( の部分文字列を探す、誤字をある程度許容した上での部分文字列特定、正規表現パターンとのマッチングなど)。接尾辞木は最長共通部分文字列問題の線形な解法の1つでもある。これらの高速化の代償として、接尾辞木に要するメモリ空間は文字列そのものを格納するのに要するメモリ空間よりもかなり大きくなる。
Remove ads
歴史
この概念は position tree として 1973年、Weiner が初めて紹介した[1]。ドナルド・クヌースはその論文を "Algorithm of the Year 1973" と評した。1976年、McCreight が構築法を大幅に単純化し[2]、1995年には Ukkonen がさらに洗練させた[3][4]。Ukkonen のアルゴリズムは接尾辞木を線形時間かつオンラインで構築する最初のアルゴリズム(文字列全体を入力する前から構築を開始できるアルゴリズム)であった。
接尾部の例
ある文字列の接尾部とは、その文字列の先頭から1文字ずつ文字を除いていった残りの部分文字列全体を指す。例えば、"BANANA" の接尾部は次のようになる。
- BANANA
- ANANA
- NANA
- ANA
- NA
- A
従って、長さ の文字列の接尾部としては、元の文字列も含めると 個の文字列が存在することになる。
定義
長さ の文字列 に関する接尾辞木は、木構造として次のように定義される ([5] page 90):
- 根から葉までのそれぞれの経路に の接尾辞(接尾部)が一対一に対応する。
- 各枝には空でない文字列が対応する。
- 根と葉以外のノードには少なくとも2つの子ノードがある。
どのような文字列にもこういった構成の木構造を構築できるわけではないので、 には本来含まれない終端記号(一般に $
で表される)を補うことがある。これにより、ある接尾部が別の接尾部の接頭部とならないようにし、 個の葉が必ず存在して、それぞれが の 個の接尾部のいずれかに対応するようにする。根以外の中間ノードは全て分岐を伴うので、中間ノードの最大個数は 個となり、全体としては最大 個のノードが存在しうる。
接尾辞木の線形時間構築の鍵となるのは「接尾辞リンク(サフィックスリンク)」である。完全な接尾辞木では、根以外の内部ノードは全て他の内部ノードへの接尾辞リンクを持つ。根からあるノードまでの経路に対応する文字列が で が1つの文字、 が(空文字列を含む)文字列であるとき、そのノードから を経路とするノードへの接尾辞リンクが存在する。図示された接尾辞木では、ANA
に対応するノードから NA
に対応するノードへ接尾辞リンクがある。接尾辞リンクは、接尾辞木を使ったアルゴリズムでも使われる場合がある。
機能
文字のサイズが一定または整数の場合、長さ の文字列 に関する接尾辞木の構築には の時間がかかる[6]。文字サイズが一定でない場合、構築時間は実装に依存する。以下では文字サイズが一定という前提でコストを表示している。そうでない場合、コストは実装に依存する。
長さ の文字列 に関する接尾辞木があるとする。あるいは、長さの総和が の文字列集合 の汎用接尾辞木があるとする。これについて、以下のような機能がある。
- 文字列検索:
- 文字列の属性検出:
接尾辞木はノード間の最も近い共通先祖 (LCA) の検索を 時間でできる([5] chapter 8)。また、以下のようなことも可能である。
Remove ads
応用
接尾辞木はバイオインフォマティクスで、DNAや蛋白質を長い文字列に見立てたパターン検索によく使われる。接尾辞木の最大の利点は、ミスマッチを許容した効率的な検索能力である。また、繰り返しのデータを検出できることからデータ圧縮にも使われ、ブロックソートのソート段階でも使われる。データ圧縮法のLZWの一種であるLZSSでも使われている。接尾辞木を使ったデータ・クラスタリングのアルゴリズムが一部の検索エンジンに使われている。
実装
要約
視点
各ノードまたは枝に要するメモリ空間を で表すと、接尾辞木全体には の空間が必要である。枝の長さ(対応する文字数)の総和は だが、各枝に対応する情報は S の部分文字列の位置と長さであり(部分文字列のコピーを枝ごとに持つ必要はない)、全体として必要なメモリ空間は ワードとなる。最悪の場合の例として、フィボナッチ列を接尾辞木で表すと、 個のノードを要する。
接尾辞木を実装する際の重要な問題として、親ノードと子ノードの関係の表し方がある。最も典型的な実装は「兄弟リスト; sibling list」と呼ばれる線形リストを使う方法である。各ノードが最初の子ノードへのポインタを持ち、子ノード同士を線形リストでつなぐ(子供同士のリストなので兄弟リスト)。ハッシュテーブル、ソート済み/未ソート配列(動的配列)、平衡2分探索木なども使われ、それぞれ実行時間特性が異なる。ここでは以下に注目する。
- ある文字に対応する子ノードを探すコスト
- 子ノードを挿入するコスト
- あるノードの全子ノードをリストアップするコスト(下表では子ノード数で割った値)
文字のサイズ(種類)を としたとき、コストは以下のようになる。
なお、挿入コストは償却計算量(amortized complexity)であり、ハッシュ操作のコストは衝突が発生しない完全ハッシュを前提としている。
各ノードや枝に情報が分散するため、接尾辞木は効率が悪く、よい実装であっても元の文字列の約10倍から20倍のメモリを消費する。接尾辞配列はこれを4倍程度に削減でき、研究者はさらなるメモリ使用量削減方法を模索している。
Remove ads
関連項目
- 接尾辞配列 (Suffix Array)
- 接尾辞トライ木
参考文献
外部リンク
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads