計算機演算法:Morris-Pratt字串搜尋演算法
原貼發表時間:2012年4月9日,作者:Stoimen
前言
我們前面已經看到,強力字串搜尋演算法和Rabin-Karp字串搜尋演算法均非有效演算法。不過,為了改進某種演算法,首先需要詳細理解其基本原理。我們已經知道,強力字串匹配的速度緩慢,並已嘗試使用Rabin-Karp中的一個雜湊函式對其進行改進。問題是,Rabin-Karp的複雜度與強力字串匹配相同,均為O(mn)。
我們顯然需要採用一種不同方法,但為了提出這種不同方法,先來看看強力字串搜尋有什麼不妥之處。事實上,再深入地研究一下它的基本原理,就能找到問題的答案了。
在強力匹配演算法中,檢視文字中的每個字元是否與模式串的第一個字元匹配。如果匹配,則順次比較模式串的第二個字元是否與文字的下一字元匹配。問題在於,當出現失配時,我們必須要在文字中回退若干位置。嗯,這種方法事實上是無法優化的。
在強力字串匹配演算法中,若出現失配,必須回退,並對比已經對比過的字元!
從上圖可以看出問題所在:一旦出現失配,必須回滾,從正文中一個已經考察過的位置開始比較。在這裡給出的示例中,我們已經查對了第一、二、三、四字母,此時模式串與文字之間出現失配,於是……於是我們就得返回去,從文字的第二個字母重新開始比較。
這一過程顯然沒有任何作用,因為我們已經知道模式串的起始字母為“a”,而且在位置1與位置3之間沒有這一字母。那我們如何消除這種不必要的重複呢?
概述
James H. Morris和Vaughan Pratt在1977年回答了這一問題,他們當時對自己的演算法進行了介紹,這種演算法會跳過大量無用對比,所以其效率高於強力字串匹配。我們來詳細地研究一下。唯一值得注意的地方就是:它利用了在對模式串與可能匹配進行對比期間收集的資訊,如下圖所示。
Morris-Pratt向前移動到下一可能匹配位置,略過一些對比!
為利用該資訊,必須首先對模式串進行預處理,以獲取後續匹配的可能位置。之後開始查詢可能的匹配結果,在發生失配時,我們可以準確地知道應當跳轉到何處,以跳過沒有任何用處的對比。
生成後續對比位置表格
這是Morris-Pratt演算法中最富有技巧性的地方,這種演算法就是通過這一步驟來克服強力字串搜尋演算法的缺陷的。讓我們來看幾張圖片。
顯然,如果模式串中僅包含不同字元,在發生失配時,應當開始將文字中的下一字元與模式串的第一字元進行對比!
不過,當模式串中存在重複字元時,如果在該字元之後出現失配,則必須從這一重複字元開始查詢可能匹配,如下圖所示。
如果模式串中包含重複字元,則“下一位置”表格會稍有不同!
最後,如果文字中的重複字元不止1個,“下一個”表格將給出其位置。
“下一個”表格中包含重複字元的位置!
有了這個包含“後續”可能位置的表格之後,就可以開始在文字中查詢模式串了。
實現
Morris-Pratt演算法的實現並不困難。首先,必須對模式串進行預處理,然後執行搜尋。以下PHP程式碼展示了具體過程。
/**
* Pattern
*
* @var string
*/
$pattern = 'mollis';
/**
* Text to search
*
* @var string
*/
$text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eleifend nisi viverra ipsum elementum porttitor quis at justo. Aliquam ligula felis, dignissim sit amet lobortis eget, lacinia ac augue. Quisque nec est elit, nec ultricies magna. Ut mi libero, dictum sit amet mollis non, aliquam et augue';
/**
* Preprocess the pattern and return the "next" table
*
* @param string $pattern
*/
function preprocessMorrisPratt($pattern, &$nextTable)
{
$i = 0;
$j = $nextTable[0] = -1;
$len = strlen($pattern);
while ($i < $len) {
while ($j > -1 && $pattern[$i] != $pattern[$j]) {
$j = $nextTable[$j];
}
$nextTable[++$i] = ++$j;
}
}
/**
* Performs a string search with the Morris-Pratt algorithm
*
* @param string $text
* @param string $pattern
*/
function MorrisPratt($text, $pattern)
{
// get the text and pattern lengths
$n = strlen($text);
$m = strlen($pattern);
$nextTable = array();
// calculate the next table
preprocessMorrisPratt($pattern, $nextTable);
$i = $j = 0;
while ($j < $n) {
while ($i > -1 && $pattern[$i] != $text[$j]) {
$i = $nextTable[$i];
}
$i++;
$j++;
if ($i >= $m) {
return $j - $i;
}
}
return -1;
}
// 275
echo MorrisPratt($text, $pattern);
複雜度
這一演算法需要一定的時間和空間進行預處理。模式串的預處理可以在O(m)內完成,其中m為模式串的長度,而搜尋本身需要O(m+n)。好訊息是預處理過程只需要完成一次,然後就可以根據需要執行任意次搜尋了!
下面的圖表給出了5字母模式串的O(n+m)複雜度,並將其與O(nm)進行對比。
應用
優點
- 其搜尋複雜度為O(m+n),快於強力演算法和Rabin-Karp演算法
- 其實現相當容易
缺點
- 需要額外的空間與時間-O(m)進行預處理
- 可以稍加優化(Knuth-Morris-Pratt)
結語
顯然,這一演算法非常有用,因為它以一種非常雅緻的方式對強力匹配演算法進行了改進。另一方面,我們必須知道還有諸如Boyer-Moore演算法等更快速的字串查詢演算法。不過,Morris-Pratt演算法在許多情況下都非常有用,所以理解其基本原理後可能會非常便利。
相關貼子:
原文標題:Computer Algorithms: Morris-Pratt String Searching 原文連結:http://www.stoimen.com/blog/2012/04/09/computer-algorithms-morris-pratt-string-searching/
相關文章
- 【技術點】計算機基礎演算法——排序 & 搜尋 & 字串匹配計算機演算法排序字串匹配
- [譯] Swift 演算法學院 - KMP 字串搜尋演算法Swift演算法KMP字串
- 【譯】Swift演算法俱樂部-暴力字串搜尋Swift演算法字串
- [譯] Swift 演算法學院 – Z-Algorithm 字串搜尋Swift演算法Go字串
- [譯] Swift 演算法學院 - Z-Algorithm 字串搜尋Swift演算法Go字串
- A*搜尋演算法概述演算法
- A*搜尋演算法(python)演算法Python
- 6.1 KMP演算法搜尋機器碼KMP演算法機器碼
- 計算機演算法計算機演算法
- 搜尋演算法合集 - By DijkstraPhoenix演算法
- 搜尋演算法總結演算法
- 演算法總結--搜尋演算法
- Sunday搜尋演算法實現演算法
- BM搜尋演算法C實現演算法
- 【演算法】深度優先搜尋(DFS)演算法
- 004.02 各類搜尋的演算法演算法
- elasticsearch演算法之搜尋模型(一)Elasticsearch演算法模型
- kmp字串匹配,A星尋路演算法KMP字串匹配演算法
- 排名演算法(二)--淘寶搜尋排序演算法分析演算法排序
- Python之 常用查詢演算法:最小項搜尋、順序搜尋、二分搜尋Python演算法
- 演算法(三):圖解廣度優先搜尋演算法演算法圖解
- 演算法篇 - 二叉搜尋樹演算法
- 【LeetCode】初級演算法:排序和搜尋LeetCode演算法排序
- 高階搜尋演算法之迭代加深演算法
- 0演算法基礎學演算法 搜尋篇第二講 BFS廣度優先搜尋的思想演算法
- 劍指offer計劃20( 搜尋與回溯演算法中等)---java演算法Java
- 0基礎學演算法 搜尋篇第一講 深度優先搜尋演算法
- 基本演算法——深度優先搜尋(DFS)和廣度優先搜尋(BFS)演算法
- 深度和廣度優先搜尋演算法演算法
- 深度優先搜尋演算法(DFS)講解演算法
- JAVA圖搜尋演算法之DFS-BFSJava演算法
- 演算法筆記(廣度優先搜尋)演算法筆記
- 每日一道演算法:搜尋插入位置演算法
- 初探富文字之搜尋替換演算法演算法
- 深度優先搜尋演算法-dfs講解演算法
- 二分搜尋演算法的實現演算法
- 必知必會JVM垃圾回收——物件搜尋演算法與回收演算法JVM物件演算法
- 資料結構與演算法 排序與搜尋資料結構演算法排序
- 電商搜尋演算法技術的演進演算法