ウッコネンのアルゴリズム

コンピュータサイエンスにおいて、ウッコネンのアルゴリズムは、 1995年にエスコ・ウッコネンによって提案された、線形時間のオンラインサフィックスツリー構築アルゴリズムです。 [ 1 ]このアルゴリズムは、文字列の最初の文字を含む暗黙のサフィックスツリーから開始されます。次に、文字列を1つずつ順に処理し、ツリーが完成するまで文字を順次追加していきます。この順序どおりの文字追加により、ウッコネンのアルゴリズムは「オンライン」という特性を持っています。 1973年にピーター・ワイナーによって提案されたオリジナルのアルゴリズムは、最後の文字から最初の文字へと、最短サフィックスから最長サフィックスへと逆方向に処理を進めていました。[ 2 ] 1976年にはエドワード・M・マクリートによって、最長サフィックスから最短サフィックスへと進む、より単純なアルゴリズムが発見されました。 [ 3 ]

暗黙の接尾辞木

Ukkonen のアルゴリズムを使用してサフィックス ツリーを生成する際に、文字列 S の文字に応じて中間ステップで暗黙的なサフィックス ツリーが表示されます。暗黙的なサフィックス ツリーでは、$ (またはその他の終了文字) ラベルを持つエッジはなく、そこから 1 つのエッジのみが出る内部ノードはありません。

ウコネンのアルゴリズムの概要

Ukkonenのアルゴリズムは、S(長さnの文字列)の各プレフィックスS[1...i]に対して、暗黙的なサフィックスツリーT iを構築します。まず、 1番目の文字を使ってT 1を構築し、次に2番目の文字を使ってT 2 を構築し、3番目の文字を使ってT 3を構築し、…、n番目の文字を使ってT n を構築します。Ukkonenのアルゴリズムを用いたサフィックスツリーには、以下の特徴があります。

  • 暗黙的なサフィックスツリー T i+1は暗黙的なサフィックスツリー T iの上に構築されます。
  • ウッコネンのアルゴリズムは、任意の時点で、これまでに見た文字の接尾辞ツリーを構築するため、オンライン特性を持ち、アルゴリズムの実行時間をO(n) にすることができます。
  • Ukkonen のアルゴリズムは n フェーズに分かれています (長さ n の文字列の各文字ごとに 1 フェーズ)。
  • 各フェーズ i+1 はさらに i+1 個の拡張に分割され、S[1...i+1] の i+1 個の接尾辞ごとに 1 つずつあります。

サフィックス拡張とは、それまでに構築されたサフィックスツリーに次の文字を追加することです。フェーズi+1の拡張jにおいて、アルゴリズムはS[j...i](前のフェーズiによって既にツリーに含まれている)の終端を見つけ、サフィックスS[j...i+1]がツリーに含まれるようにS[j...i]を拡張します。拡張ルールは3つあります。

  1. S[j...i]というラベルが付いたルートからのパスがリーフエッジで終了する場合(つまり、S[i]がリーフエッジの最後の文字である場合)、文字S[i+1]はそのリーフエッジのラベルの末尾に追加されます。
  2. S[j...i]というラベルのルートからのパスが非リーフエッジで終了している場合(つまり、パス上でS[i]の後に文字がさらに存在する場合)、次の文字がS[i+1]でない場合、文字S[i+1]から始まるラベルS[i+1]と番号jを持つ新しいリーフエッジが作成されます。S[1...i]が非リーフエッジの内側(中間)で終了している場合も、新しい内部ノードが作成されます。
  3. S[j..i]というラベルが付いたルートからのパスが非リーフエッジで終了し(つまり、パス上でS[i]の後にさらに文字がある)、次の文字がS[i+1](すでにツリー内にある)である場合は、何も行いません。

重要な点として、特定のノード(ルートノードまたは内部ノード)からは、1つの文字から始まるエッジは1つだけ存在します。同じ文字から始まるエッジが1つ以上存在することはありません。

実行時間

今後、接尾辞木を生成するための単純な実装では、 big O記法O ( n 2 )、あるいはO ( n 3 )の時間計算量が必要となる(nは文字列の長さ)。Ukkonenは、様々なアルゴリズム手法を駆使することで、定数サイズのアルファベットではこれをO ( n ) (線形)時間、一般的にはO ( n log n )にまで短縮し、前述の2つのアルゴリズムの実行時性能と同等の性能を実現した。

ウッコネンのアルゴリズムの例

Ukkonen のアルゴリズムを使用した最終サフィックス ツリー (例)。

Ukkonen のアルゴリズムを使用してサフィックス ツリーがどのように構築されるかをわかりやすく説明するために、文字列 を考えてみましょうS = xabxac

  1. 空のルートノードから開始します。
  2. 文字列の最初の文字を追加してfor を構築します。ルール2が適用され、新しいリーフノードが作成されます。T1{\displaystyle T_{1}}S[1]
  3. (と)の接尾辞を追加してfor を構築します。ルール1が適用され、既存のリーフエッジのパスラベルが拡張されます。ルール2が適用され、新しいリーフノードが作成されます。T2{\displaystyle T_{2}}S[1..2]xaxaa
  4. ( 、および)の接尾辞を追加してを構築します。ルール1が適用され、既存のリーフエッジのパスラベルが拡張されます。ルール2が適用され、新しいリーフノードが作成されます。T3{\displaystyle T_{3}}S[1..3]xabxababb
  5. 接尾辞( 、、 )を追加してfor を構築します。ルール1が適用され、既存のリーフエッジのパスラベルが拡張されます。ルール3が適用され、何も行われません。T4{\displaystyle T_{4}}S[1..4]xabxxabxabxbxx
  6. 接尾辞(、、、 )を追加してを構築します。ルール1が適用され、既存のリーフエッジのパスラベルが拡張されます。ルール3が適用され、何も行われません。T5{\displaystyle T_{5}}S[1..5]xabxaxabxaabxabxaxaa
  7. の接尾辞(、、、、)を追加してを構築します。ルール1が適用され、既存のリーフエッジのパスラベルが拡張されます。ルール2が適用され、新しいリーフノードが作成されます(この場合、3つの新しいリーフエッジと2つの新しい内部ノードが作成されます)。T6{\displaystyle T_{6}}S[1..6]xabxacxabxacabxacbxacxacacc

参考文献

  1. ^ Ukkonen, E. (1995). 「オンラインサフィックスツリー構築」(PDF) . Algorithmica . 14 (3): 249– 260. CiteSeerX  10.1.1.10.751 . doi : 10.1007/BF01206331 . S2CID  6027556 .
  2. ^ Weiner, Peter (1973). 「線形パターンマッチングアルゴリズム」(PDF) . 14th Annual Symposium on Switching and Automata Theory (SWAT 1973) . pp.  1– 11. CiteSeerX 10.1.1.474.9582 . doi : 10.1109/SWAT.1973.13 . 2016年3月3日時点のオリジナル(PDF)からのアーカイブ。 2013年2月4日閲覧 
  3. ^ McCreight, Edward Meyers (1976). 「スペースを節約したサフィックスツリー構築アルゴリズム」. Journal of the ACM . 23 (2): 262– 272. CiteSeerX 10.1.1.130.8022 . doi : 10.1145/321941.321946 . S2CID 9250303 .