180 likes | 334 Views
その他の話題. 文字列照合 5/21 分枝限定法 5/26 動的計画法 5/28. 文字列照合 (string matching). 二つの文字列( テキスト と パターン )が与えられたとき,テキスト中にパターンが現れるかどうか調べ,もし現れるならば,その最初の位置を答えよ. エディタ等,実用上重要な問題. 通常,テキスト長 n >> パターン長 m 例:テキスト a string searching example consisting of simple text パターン ing. 文字列照合(つづき).
E N D
その他の話題 • 文字列照合 5/21 • 分枝限定法 5/26 • 動的計画法 5/28
文字列照合 (string matching) • 二つの文字列(テキストとパターン)が与えられたとき,テキスト中にパターンが現れるかどうか調べ,もし現れるならば,その最初の位置を答えよ. • エディタ等,実用上重要な問題. • 通常,テキスト長n >> パターン長m • 例:テキスト a string searching example consisting ofsimple text パターン ing
文字列照合(つづき) • 文字列:文字を要素とする配列で表現(添字0は番兵に使う).答えは,テキスト中で最初に現れたパターンの左端位置とする. • 例:テキスト (配列 text) n=52 a string searching example consisting of ... 012345 : 番地(配列の添字) パターン (配列pattern) m=3 ing 0123 • 答え: 6
素朴なアルゴリズム • (プログラム5.1.1の概要設計) % パターンがあるとき最初のパターンの左端位置, % ないとき,0を返す. for ( i=1 ; i<=n-m+1 ; i++) { for ( j=1 ; j<=m ; j++) if (text[i+j-1]!=pattern[j]) break ; return (i) ; } return (0) ; 例:テキスト a string searching example consisting of ... パターン ing
Boyer-Mooreのアルゴリズム(BM法) • 照合は,パターンの右端から行う. • 照合に失敗したとき,テキスト側の文字(作戦1)や,既に照合済みの部分(作戦2)を利用して,パターンをできるだけたくさん右にずらす. (作戦1の説明)パターン sting テキスト a string searching example consisting of ... stingsting stingstingstingstingsting sting
BM法のアイディア(つづき) (作戦2の説明)パターン 101001 テキスト 110101001 101001 101001
BM法 –作戦1(前処理) テキスト • 各文字cについて,i をずらす量skip[c]をあらかじめ計算しておく. (プログラム5.1.7の概要設計) for(テキスト中に現れうるすべての文字cについて) skip[c] = m ; for (j=1; j<m; j++) skip[pattern[j]] = m-j ; x 次はここから比較 x a x パターン x a x i をこれだけずらしてよい(ずらす量=skip[x])
BM法 –作戦1(前処理,つづき) pattern=never (m=5) に対するskip[・]の計算経過 • 空欄は値の書き込みが起こらなかったことを表す(空欄の値はその上の値と同じ). j n e v r その他の文字 0 5 5 5 5 5 1 4 2 3 3 2 4 1 (結果) 4 1 2 5 5
作戦1のみのアルゴリズム (プログラム5.1.8の概要設計) i=m; %iをテキストのm番目の文字に while (iがテキスト内) { j=m; %jをパターンの右端に while (jがパターン内) if(text[i]==text[j]) iとjを1つ左に動かす; else (*)へとぶ; return(i+1); %見つかった (*)i=i+max(skip[text[i]], m-j+1) %ずらした後のパターン右端に対応する位置にiを移動 } return (0); %見つからなかった
作戦1のみのアルゴリズム(補足) (*)i=i+max(skip[text[i]], m-j+1) の理由. i テキスト x j パターン x x これでは意味がない skip[x] m-j+1 ここに移動
BM法 –作戦2 • patternの左からj番目の文字(pattern[j])で照合に失敗したとする.照合に成功した文字列pattern[j+1~m]を利用し,パターンをなるべくたくさん右にずらす. i テキスト ずらす量next[j]=m-j+s x 次はここから比較 1 j m y パターン z s j-s y≠z 場合1
BM法 –作戦2(つづき) ずらす量next[j]=m-j+s i テキスト x 1 j m y パターン s 場合2, 3
next の計算(アイディア) • pattern内の各位置 j について,i をずらす量next[j]をあらかじめ以下のように計算する. • パターンを s だけずらして自分自身と重ねてみる.右からみて初めて異なる位置を j とする.m-j+s がずらす量next[j]の候補である. 1 j m y パターン z y≠z s j-s m-s 1 j m y パターン s 1 m-s
next の計算(アイディア,つづき) • 「照合の見落とし」がないようにするためには,ずらす量sが一番小さい場合を選ばなければならない. 1 j m y パターン z y≠z s j-s m-s * j=6 c b c b c a b c (m=8) s=3 c b c b c a b c m-j+s=8-6+3=5 s=5 c b c b c a b c m-j+s=8-6+5=7 ○ ×
nextの計算例 s j m-j+s c b c b c a b c 8 8 8 15 14 13 12 11 10 9 8 7 7 8 14 13 12 11 10 9 8 6 8 6 6 5 6 7 7 4 8 4 4 3 6 5 5 2 8 2 2 1 8 1 1 (結果) 14 13 12 11 10 5 8 1 pattern=cbcbcabcに対するnext[・]の計算経過 • 空欄は値の書き込みが起こらなかったことを表す(空欄の値はその上の値と同一).
nextの計算アルゴリズム (プログラム5.1.15の概要設計) pattern[0]=番兵; %番兵はパターンに現れない文字 for(s=m;s>0;s--) {%なるべく小さいsを探すためsの降順 j=m; while(pattern[j-s]==pattern[j]) j--; %文字の異なる位置が見つかった if (j>s) next[j]=m-j+s ; %場合1 else while (j>0) {%場合2,3 next[j]=m-j+s ; j-- } }
BM法 -- 完成版 (プログラム5.1.22の概要設計) pattern[0]=番兵1; %番兵1はテキストに現れない文字 text[0]=番兵2; %番兵1≠番兵2 i=m; %iをテキストのm番目に while (iがテキスト内) { j=m; %jをパターンの右端に while (text[i]==pattern[j]) {i--; j--;} if (j==0) return(i+1); %見つかった i=i+max(skip[text[i]],next[j]); %ずらした後のパターン右端に対応する位置にiを移動 } return (0) ;
時間計算量 • BM法の作戦1は,パターンの右端近くで照合に失敗したとき/テキストに現れる文字種が多いとき有効. • 特に,パターン右端の文字が照合せず,そのときのテキスト側の文字がパターン中に現われていなければ,パターンを一気にmだけ右に動かせる.この場合,文字の比較はテキスト中でm字おきにしか行われない.すなわち,テキスト末尾まで行ったとしても,約n/m回の比較ですむ.