まず、アルゴリズムはサフィックスを元の順序、つまり入力文字列に現れる順序で処理することを理解することが重要です。辞書順ではありません。
したがって、入力文字列が の場合、abxabc
最初に、次にabxabc
、というように考慮されます。bxabc
xabc
この順序で考慮する接尾辞ごとに、辞書編集上の前身(*)である接尾辞の位置を決定します (したがって、ここでは、ここでのみ、辞書編集順序の概念を使用します)。最初の接尾辞abxabc
の場合、辞書編集上の前身、つまり辞書編集上の接尾辞の順序でその直前に現れる接尾辞は ですabc
。C
これは、この目的のために特別に用意された配列内の O(1) ルックアップによって決定されます。
abxabc
内側のループは、 と の文字をabc
1 つずつ比較し、これら 2 つのサフィックスの最初の 2 文字が共通していることを判別します。これはコード内の変数l
であり、接尾辞の LCP のエントリはabxabc
2 でなければならないことを意味するため、 を設定しLCPadj[i] = l
ます。i
ここでは、接尾辞配列内の位置ではなく、入力文字列内の接尾辞の位置を参照することに注意してください。LCPadj
LCP アレイも (まだ)そうではありません。これは補助データ構造です。
次に、次の文字列に進みますbxabc
。再び、それがその辞書編集上の前任者であることを検出するために使用C
しbc
、2 つが共有するプレフィックス文字の数を決定します。そして、ここに秘訣があります。これは、少なくとも前のステップ (つまり 2) から 1 を引いた数でなければなりません。なぜでしょうか? 現在検討している文字列bxabc
はもちろん、以前に検討した文字abxabc
列 ( ) の接尾辞であるため、その文字列の辞書編集上の前身 ( abc
) も 1 文字短い接尾辞 (bc
)、そしてその接尾辞も接尾辞配列のどこかにある必要があり、その接頭辞を現在考慮されている文字列から最初の文字を除いたものと共有する必要があります。さらに、現在考慮されている文字列に短く、辞書編集的に近い接尾辞は他にありません。辞書式ソートがどのように機能するかを考えると、後者は非常に論理的ですが、これの正式な証明もあります (たとえば、ここでの Kärkkäinen の講義の Lemma 5.10 ) 。
これが、ここでの主な原理の説明です。各変数の役割を完全に理解するために、コードについて注意すべき点がいくつかあります。
- 説明したように、
C
は補助配列 (n
長さは整数) であり、入力文字列の各接尾辞について、辞書編集上の直前の接尾辞である他の接尾辞の位置を格納します。この配列は、左から右にではなく、(賢明なことに) 接尾辞配列を左から右にたどって構築されます。これにより、任意の文字列の直前の辞書編集上の先行を簡単に判別できるためです。位置で始まる接尾辞の直前の辞書編集上の先行suffixArr[i]
もちろん位置に配置する必要がありますsuffixArr[i-1]
。C
これがどのように定義されているかをコードで確認してください。
- 前述のよう
LCPadj
に、サフィックス配列に現れる順序ではなく、入力文字列に現れる順序でサフィックスの LCP 値を保存します。これが、出力時に が左から右に出力されるのでLCPadj
はなく、サフィックス配列を左から右に通過し、LCPadj[i]
その順序で出力される理由です。これが当てはまることを確認します。
これが役立つことを願っています。そうでない場合はお知らせください。
(*)辞書編集上の前任者とは、辞書編集的に順序付けられた接尾辞のリスト内の接尾辞の直前の前任者、つまり、接尾辞配列内のすぐ左にある接尾辞を意味します。