好後綴規則 (長度 1)
比對方向 ← 01234 QQQQCCCABC X| CCABC 01234 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:C (壞字符右邊的字。位於$Text。 $Key也有相同的字 ) 好後綴位置:4 (總是 最大索引值 4) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴C」對齊的字: $Key[0]到 $Key[3] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴相同的字的位置:1 額外檢查: 位置 1 的左邊的字:C 「$Key裡的好後綴」的左邊的字:B (它和壞字符比對失敗過) 以上兩者不相同,所以可以移到 位置1 移動格數:好後綴位置 - 找到的位置 4 - 1 = 3 QQQQCCCABC | CCABC 找到C對齊,移動3格 有 2 個 C 找距離「好後綴」最近的那個
額外檢查失敗的例子 比對方向 ← 01234 QQQQCBCABC X BCABC 01234 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:C (壞字符右邊的字。位於$Text。 $Key也有相同的字 ) 好後綴位置:4 (總是 最大索引值 4) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴C」對齊的字: $Key[0]到 $Key[3] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴相同的字的位置:1 額外檢查: 位置 1 的左邊的字:B 「$Key裡的好後綴」的左邊的字:B (它和壞字符比對失敗過) 以上兩者相同,所以不可以移到 位置 1 QQQQCBCABC X| BCABC 勉強移到 位置 1的結果 C可以對齊 但B不行。就像上次那樣 QQQQCBCABC | BCABC 最後,沒有找到可以對齊的 移動格數:4 - (-1) = 5
左邊沒有東西、不用額外檢查 比對方向 ← 01234 QQQQCCAABC X CAABC 01234 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:C (壞字符右邊的字。位於$Text。 $Key也有相同的字 ) 好後綴位置:4 (總是 最大索引值 4) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴C」對齊的字: $Key[0]到 $Key[3] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴相同的字的位置:0 位置 0 的左邊的字:沒有 不用額外檢查了 移動格數:好後綴位置 - 找到的位置 4 - 0 = 4 QQQQCCAABC | CAABC 找到C對齊,移動4格
好後綴規則(長度 1) vs 壞字符規則
兩者很像。以下是它們的差別。 $i 為比對失敗位置 尋找範圍: Bc:$Key[$i]的左邊 Gs:$Key[-1]的左邊 ($Key最後一個字的左邊) 符合的條件: Bc:和「壞字符」一樣 Gs: 1. 和「好後綴」($Key最後一個字) 一樣 2. 需要作「額外檢查」 需不需要去猜「壞字符」是什麼? Bc:需要。 因此,製表時需要較大的空間 $B4 = @( 4 - (-1) ) * 256 使用表格時,需要知道「壞字符」是什麼 [int]$badChar = $Text[$base + $i] if ( $Bc[$i][ $badChar ] -gt $Gs[$i] ) Gs:不需要。
好後綴規則 (長度 2)
比對方向 ← 012345 QQQQBCBBCABC X BBCABC 012345 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:BC (壞字符右邊的那些字。位於$Text。 $Key也有相同的字 ) 好後綴位置:5 (總是 最大索引值 5) (它有兩個字,以5來代表) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴BC」對齊的字: $Key[0]到 $Key[4] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴BC相同的字的位置:2 (它有兩個字,以索引2來代表) 額外檢查: 位置 2(和位置1)的左側的字:B 「$Key裡的好後綴」的左側的字:A (它和壞字符比對失敗過) 以上兩者不相同,所以可以移到 位置 2 移動格數:好後綴位置 - 找到的位置 5 - 2 = 3 012345 QQQQBCBBCABC || BBCABC 找到BC,而且左邊不同 移動格數:5 - 2 = 3
額外檢查失敗的例子 比對方向 ← 012345 QQQQBCABCABC X ABCABC 012345 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:BC (壞字符右邊的那些字。位於$Text。 $Key也有相同的字 ) 好後綴位置:5 (總是 最大索引值 5) (它有兩個字,以5來代表) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴BC」對齊的字: $Key[0]到 $Key[4] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴BC相同的字的位置:2 (它有兩個字,以索引2來代表) 額外檢查: 位置 2(和位置1)的左側的字:A 「$Key裡的好後綴」的左側的字:A (它和壞字符比對失敗過) 以上兩者相同,所以不可以移到 位置 2 QQQQBCABCABC X|| ABCABC 勉強移到 位置 2的結果 BC可以對齊 但A不行。就像上次那樣 QQQQBCABCABC | ABCABC 最後,沒有找到可以對齊的 移動格數:5 - (-1) = 6
左邊沒有東西、不用額外檢查 比對方向 ← 012345 QQQQBCBCCABC X BCCABC 012345 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:BC (壞字符右邊的那些字。位於$Text。 $Key也有相同的字 ) 好後綴位置:5 (總是 最大索引值 5) (它有兩個字,以5來代表) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴BC」對齊的字: $Key[0]到 $Key[4] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴BC相同的字的位置:1 (它有兩個字,以索引1來代表) 額外檢查: 位置 1(和位置0)的左側的字:沒有 不用額外檢查了 移動格數:好後綴位置 - 找到的位置 5 - 1 = 4 012345 QQQQBCBCCABC || BCCABC 找到BC BC左邊沒有東西,不用額外檢查 移動格數:5 - 1 = 4
部份好後綴、不用額外檢查 比對方向 ← 012345 QQQQBCCABABC X CABABC 012345 移動方向 → 壞字符:Q 壞字符位置:3 好後綴:BC (壞字符右邊的那些字。位於$Text。 $Key也有相同的字 ) 好後綴位置:5 (總是 最大索引值 5) (它有兩個字,以5來代表) 尋找範圍: 在後續移動過程中,仍有機會和「$Text裡的好後綴BC」對齊的字: $Key[0]到 $Key[4] (那些字總是位於 $Key最後一個字的左邊 ) 和好後綴BC相同的字的位置:沒有 和「部份好後綴C」相同的字的位置:0 額外檢查: 因為是部份好後綴,不用額外檢查了 移動格數:好後綴位置 - 找到的位置 5 - 0 = 5 012345 QQQQBCCABABC | CABABC 當「完整版的後綴」找不到,「部份版的」也可以 只對齊C即可 移動格數:5 - 0 = 5
找到的對齊位置有兩種
1.通過額外檢查的位置 不能對齊「其他長度的好後綴」 比對方向 ← 0123456 QQQQQBCBBBCABC X BBBCABC 移動方向 → 找到的位置3:長度 2 好後綴專用。不能對齊「其他長度的好後綴」 長度 2 好後綴 0123456 QQQQQBCBBBCABC || BBBCABC 長度 1 好後綴 0123456 QQQQQQCBBBCABC X| BBBCABC 長度 3 好後綴 0123456 QQQQABCBBBCABC X|| BBBCABC 長度 4 好後綴 0123456 QQQCABCBBBCABC X|| BBBCABC
2.不用額外檢查的位置 (左邊沒有東西) 「長度大於、等於它」的好後綴可以和它對齊 「長度 小於 它 」的好後綴不能和它對齊 比對方向 ← 0123456 QQQQQBCBCACABC X BCACABC 移動方向 → 「長度 大於、等於 2 」的好後綴可以和它對齊 「長度 小於 2 」的好後綴不能和它對齊 長度 2 好後綴 0123456 QQQQQBCBCACABC || BCACABC 長度 1 好後綴 0123456 QQQQQQCBCACABC X| BCACABC 長度 3 好後綴 0123456 QQQQABCBCACABC || BCACABC 長度 4 好後綴 0123456 QQQCABCBCACABC || BCACABC
開始製表 $Gs
方法一: 根據比對失敗位置,計算好後綴長度 在可能的對齊位置,逐一確認:是否和好後綴相同?
$Key = 'BCABC' $Gs = @( 5 ) * 5 <# 結果: $Gs[0] = $Gs[1] = $Gs[2] = $Gs[3] = $Gs[4] = 5 $Gs是一個陣列、有5個元素。每個元素的值都是5 元素的索引值:比對失敗位置 元素的值:比對失敗發生時,要移動的距離 先假設找不到可以對齊的位置 移動距離 = 好後綴位置 - 找不到 = 4 - (-1) = 5 位置 4 沒有好後綴,稍後會再設值 $Gs[4] = 1 #> #========= 設定 $Gs[3] =========== #====== step 1:根據比對失敗位置,計算好後綴長度===== #好後綴位置 = 總是最後面的索引值 $good = 4 #好後綴長度 = 好後綴位置 - 比對失敗位置 $len = 4 - 3
#====== step 2:在可能的對齊位置,逐一確認:是否和好後綴相同?===== # $test 是可能的對齊位置 從 位置 3 開始找 # 位置 3 = 好後綴位置的左邊 = $good - 1 for($test = 3; $test -ge 0; $test--){ $g = $good $t = $test # $L -gt 0 表示:好後綴 還沒比對完 # $t -ge 0 表示:$Key[$t]還有字可以參加比對 # 如果 $t -lt 0 $Key[$t]已經沒有字可以參加比對 # 儘管 $L -gt 0 好後綴還沒比對完,也會停止比對 # 不斷使$g 和 $t 向左移動、進行比對 for ($L = $len ; $L -gt 0 -and $t -ge 0 ; $g--,$t--,$L--){ # 如果比對失敗,這個位置不可以對齊 if ($Key[$g] -ne $Key[$t]) {break} } #======== $Key[$t]已經沒有字可以參加比對 ======= # $t 對齊範圍左端 對齊範圍右端 # -1 0 $test # # $g $g + 1 $good # 好後綴的左端 好後綴的右端 # 也可以寫成 $Gs[3] = $g - $t if ($t -eq -1) { $Gs[3] = $good - $test ;break} #============ 好後綴比對完成 =============== # 而且,$Key[$t]還有字可以參加比對 # 檢查左側是否「不相同」 # 此時的 $t $g 為左側 # 左側 對齊範圍左端 對齊範圍右端 # $t $t + 1 $test # # $g $g + 1 $good # 左側 好後綴的左端 好後綴的右端 # # 也可以寫成 $Gs[3] = $g - $t # # 此時的 $g 也是 比對失敗位置 # 也可以寫成 $Gs[$g] = $g - $t if ($L -eq 0) { if ($Key[$g] -ne $Key[$t]) {$Gs[3] = $good - $test ;break } } } #上面只是$Gs[3]的設值,還有$Gs[2] $Gs[1] $Gs[0]和上例類似 #位置 4沒有好後綴 $Gs[4] = 1
方法二: 確認每個可能的對齊位置(從右邊開始 ),可以符合多少後綴長?
藉由所符合的後綴長,推得在哪一個「比對失敗位置」發生時,可以和好後綴對齊
$Key = 'BCABC' $Gs = @( 5 ) * 5 <# 結果: $Gs[0] = $Gs[1] = $Gs[2] = $Gs[3] = $Gs[4] = 5 $Gs是一個陣列、有5個元素。每個元素的值都是5 元素的索引值:比對失敗位置 元素的值:比對失敗發生時,要移動的距離 先假設找不到可以對齊的位置 移動距離 = 好後綴位置 - 找不到 = 4 - (-1) = 5 位置 4 沒有好後綴,稍後會再設值 $Gs[4] = 1 #> #好後綴位置 = 總是最後面的索引值 $good = 4 # $test 是可能的對齊位置 從 位置 3 開始找 # 位置 3 = 好後綴位置的左邊 = $good - 1 for($test = 3; $test -ge 0; $test--){ $g = $good $t = $test # 使$g 和 $t 持續向左移動、進行比對 # $t 可能會到達最左邊(接下來,就沒有字了) for ( ; $t -ge 0 ; $g--,$t--){ if ($Key[$g] -ne $Key[$t]) {break} } if ($t -eq $test){ # ===== 可能 1 :$t根本沒移動。符合 0 個 後綴長 ====== }elseif($t -eq -1){ # === 可能 2 :$t 已經到達 $Key的最前面了,沒有字可供繼續比對了=== # 符合的後綴長 等於 ($test + 1) 也等於 ($good - $g) # 比對失敗位置 等於 好後綴位置 - 符合的後綴長 # 等於 $good - ($test + 1) # 也等於 $g # $t 對齊範圍左端 對齊範圍右端 # -1 0 $test # # $g $g + 1 $good # 比對失敗位置 好後綴的左端 好後綴的右端 #如果仍是預設值,才設值 if ($Gs[$g] -eq 5){$Gs[$g] = $good - $test} # 比對失敗位置 $g 左邊的那些位置: 0 到 ($g - 1) # 所需要對齊的後綴長 大於 $test所提供的長度 # $test 可以和這些比對失敗位置的好後綴對齊 for ($i = 0; $i -lt $g; $i++){ #如果仍是預設值,才設值 if ($Gs[$i] -eq 5){$Gs[$i] = $good - $test} } }else{ #===== 可能 3 :$t 移動了幾格。符合了幾格後綴長 ====== # $t 介於 「完全不動」和「沒有字可比對」 之間 # 符合的後綴長 等於 ($test - $t) 也等於 ($good - $g) # 比對失敗位置 等於 好後綴位置 - 符合的後綴長 # 等於 $good - ($test -$t) # 也等於 $g # 左側不同 對齊範圍左端 對齊範圍右端 # $t $t + 1 $test # # $g $g + 1 $good # 比對失敗位置 好後綴的左端 好後綴的右端 #如果仍是預設值,才設值 if ($Gs[$g] -eq 5){$Gs[$g] = $good - $test} } } #位置 4沒有好後綴 $Gs[4] = 1
方法三: 確認每個可能的對齊位置(從最左邊開始 ),可以符合多少後綴長?
藉由所符合的後綴長,推得在哪一個「比對失敗位置」發生時,可以和好後綴對齊
$Key = 'BCABC' $Gs = @( 5 ) * 5 <# 結果: $Gs[0] = $Gs[1] = $Gs[2] = $Gs[3] = $Gs[4] = 5 $Gs是一個陣列、有5個元素。每個元素的值都是5 元素的索引值:比對失敗位置 元素的值:比對失敗發生時,要移動的距離 先假設找不到可以對齊的位置 移動距離 = 好後綴位置 - 找不到 = 4 - (-1) = 5 位置 4 沒有好後綴,稍後會再設值 $Gs[4] = 1 #> #好後綴位置 = 總是最後面的索引值 $good = 4 #移動距離的預設值 $defaultMove = 5 # $test 是可能的對齊位置,從最左邊開始找。 for($test = 0; $test -le 3; $test++){ $g = $good $t = $test # 使$g 和 $t 持續向左移動、進行比對 # $t 可能會到達最左邊(接下來,就沒有字了) for ( ; $t -ge 0 ; $g--,$t--){ if ($Key[$g] -ne $Key[$t]) {break} } if ($t -eq $test){ # ===== 可能 1 :$t根本沒移動。符合 0 個 後綴長 ====== # 原本想要符合的後綴長 ($test + 1 ) # 比對失敗位置 等於 好後綴位置 - 符合的後綴長 # 等於 $good - ($test + 1 ) # 使用預設值 $Gs[$good - $test -1 ] = $defaultMove }elseif($t -eq -1){ # === 可能 2 :$t 已經到達 $Key的最前面了,沒有字可供繼續比對了=== # 符合的後綴長 等於 ($test + 1) 也等於 ($good - $g) # 比對失敗位置 等於 好後綴位置 - 符合的後綴長 # 等於 $good - ($test + 1) # 也等於 $g # $t 對齊範圍左端 對齊範圍右端 # -1 0 $test # $g $g + 1 $good # 比對失敗位置 好後綴的左端 好後綴的右端 $Gs[$g] = $good - $test #修改移動距離的預設值 $defaultMove = $good - $test # 比對失敗位置 $g 左邊的那些位置: 0 到 ($g - 1) # 所需要對齊的後綴長 大於 $test所提供的長度 # $test 可以和這些比對失敗位置的好後綴對齊 # $Gs[0] 到 $Gs[$g - 1] 都可以設值為 $good - $test # 在此先不設值,而是把值先存到 $defaultMove # $test 在之後的回合裡,會向右移動 # 會陸續設定 $Gs[$g - 1] 到 $Gs[0] # 等到沒找到更適合的值,再使用 $defaultMove }else{ #===== 可能 3 :$t 移動了幾格。符合了幾格後綴長 ====== # 此處的$t 介於 「完全不動」和「$Key最前面」 之間 # 符合的後綴長 等於 ($test - $t) 也等於 ($good - $g) # 比對失敗位置 等於 $good - ($test -$t) # 也等於 $g # 左側不同 對齊範圍左端 對齊範圍右端 # $t $t + 1 $test # # $g $g + 1 $good # 比對失敗位置 好後綴的左端 好後綴的右端 $Gs[$g] = $good - $test # 原本想要符合的後綴長 ($test + 1 ) # 比對失敗位置 等於 好後綴位置 - 符合的後綴長 # 等於 $good - ($test + 1 ) # 使用預設值 $Gs[$good - $test -1 ] = $defaultMove } } #位置 4沒有好後綴 $Gs[4] = 1
沒有留言:
張貼留言