串的模式匹配在串的各種操作中是經常用到的算法。串的模式匹配也成為子串的定位操作,即查找子串在主串中出現的位置。本文主要講解串的經典模式匹配算法—Brute-Force。
1 基本思想
串的模式匹配也稱為子串的定位操作。設有主串S和子串T,如果在主串S中找到一個與子串T相等的子串,則返回串T的第一個字符在串S中的位置。其中S稱為目標串,子串T又稱為模式串。
Brute-Force的基本思想是:從主串S=“S(0) S1 ...S(n-1)”的第pos個字符開始與子串T=“T(0) T1 ...T(n-1)”的第一個字符比較,如果相等則繼續比較后一個字符;否則從主串的下一字符開始與子串T的第一個字符重新開始比較,以此類推。如果在主串S中存在與子串T相等的連續字符序列,則匹配成功,函數返回子串T中第一個字符在主串S中的位置;否則,函數返回-1。簡單的說,就是對主串的每一個字符作為子串的開頭,與要匹配的字符串進行匹配。對主串做大循環,每個字符開頭做T的長度的小循環,直到匹配成功或全部遍歷完成為止。
假設我們要從主串S=“goodgoogle”中,找到T=“google”這個子串的位置。步驟如下:
1. 主串S的第一位開始,S與T得前三個字母都匹配成功,但S得第四個字母是d而T的是g。第一位匹配失敗。如圖所示,豎直連線表示相等,彎折線表示不等。
2. 主串S第二位開始,主串S首字母為o,模式串T的首字母為g,匹配失敗,如圖所示:
3.主串S第三位開始,主串S首字母為o,模式串T的首字母為g,匹配失敗,如圖所示:
4.主串S第四位開始,主串S首字母為d,模式串T的首字母為g,匹配失敗,如圖所示:
5.主串S第五位開始,S與T,6個字母全匹配,匹配成功,如圖所示:
2 算法實現
假設串采用順序存儲方式存儲,並假設主串S和模式串T的長度存在S[0]和T[0]中,則Brute-Force匹配算法如下:
1: /* 返回子串T在主串S中第pos個字符之后的位置。若不存在,則函數返回值為0 */
2: /* T非空,1<=StrLength(S) 。*/
3: int B_FIndex( String S , String T , int pos )
4: {
5: int i = pos ; //i用於主串S中當前位置下標,若pos不為1,則從pos位置開始匹配
6: int j = 1 ; //j用於子串T中當前位置下標
7: while ( i<= S[0] && j <= T[0] ) //若i小於S長度且j小於T長度時循環
8: {
9: if ( S[i] == T[j] ) //兩字母相等時繼續
10: {
11: ++i ;
12: ++j ;
13: }
14: else //指針退回重新開始匹配
15: {
16: i = i - j + 2 ; //i退回上次匹配首位的下一位
17: j = 1 ; //j退回子串T的首位
18: }
19: }
20: if ( j > T[0] )
21: return i - T[0] ;
22: else
23: return 0 ;
24: }
3 算法分析
Brute-Force匹配算法簡單、易於理解,但是執行效率不高。在此算法中,即使主串與子串已有多個字符經過比較且相等,但只要有一個字符不相等,就需要將主串的比較位置退回。
例如,假設主串S=“aaaaaaaaaaaaab”,子串T=“aaab”。其中n=14 ,m=4。每次比較子串的最后一個字符與主串中的字符不相等,所以均需將主串的指針退回,從主串的下一個字符開始與子串的第一個字符重新比較。在整個匹配過程中,主串的指針需要退回9次,匹配不成功的比較次數10*4,成功匹配的比較次數4次,總的比較次數為10*4+4=11*4 ,即( n–m+1)*m 。
設主串的長度為n,子串的長度為m。Brute-Force匹配算法在最好的情況下,即主串的前m個字符剛好與子串相等,時間復雜度為O(m)。在最壞的情況下,Brute-Force匹配算法的時間復雜度為O(n*m)。