五.其他表示模式值的方法
上面那種串的模式值表示方法是最優秀的表示方法,從串的模式值我們可以得到很多資訊,以下稱為第一種表示方法。第二種表示方法,雖然也定義
next[0]= -1,
但後面絕不會出現
-1,除了
next[0]
,其他模式值
next[j]=k(0
≤k的意義可以簡單看成是:下標為
j的字元的前面最多
k個字元與開始的
k個字元相同,這裡並不要求
t[j] != t[k]
。其實next[0]
也可以定義為
0(後面給出的求串的模式值的函式和串的模式匹配的函式,是
next[0]=0
的),這樣,
next[j]=k(0
≤k的意義都可以簡單看成是:下標為
j的字元的前面最多
k個字元與開始的
k個字元相同。第三種表示方法是第一種表示方法的變形,即按第一種方法得到的模式值,每個值分別加
1,就得到第三種表示方法。第三種表示方法,我是從論壇上看到的,沒看到詳細解釋,我估計是為那些這樣的程式語言準備的:陣列的下標從
1開始而不是0。
下面給出幾種方法的例子:
表一。 下標
0 12 3
4 56 7
8 ta b
a bc a
a bc
(1) next -1
0 -1
0 2-1 1
0 2(2) next
-1 0
0 1
2 0
1 1
2 (3) next 0
1 0
1 3
0 2
1 3
第三種表示方法
,在我看來,意義不是那麼明了,不再討論。
表二。 下標
0 12 3
4 ta b
c ac
(1)next -1
0 0-1 1
(2)next
-1 0
0 0
1 表三。 下標
0 12 3
4 56 7
t ad c
a dc a
d(1)next -1
0 0-1 0
0 -1
0(2)next
-1 0
0 0
1 2
3 4
對比串的模式值第一種表示方法和第二種表示方法,看錶一:
第一種表示方法
next[2]= -1,
表示t[2]=t[0]
,且t[2-1] !=t[0]
第二種表示方法
next[2]= 0,
表示t[2-1] !=t[0],
但並不管
t[0]
和t[2]
相不相等。
第一種表示方法
next[3]= 0,
表示雖然
t[2]=t[0]
,但t[1] ==t[3]
第二種表示方法
next[3]= 1,
表示t[2] =t[0],
他並不管
t[1]
和t[3]
相不相等。
第一種表示方法
next[5]= -1,
表示t[5]=t[0]
,且t[4] !=t[0]
,t[3]t[4] !=t[0]t[1]
,t[2]t[3]t[4] !=t[0]t[1]t[2]
第二種表示方法
next[5]= 0,
表示t[4] !=t[0]
,t[3]t[4] !=t[0]t[1]
,t[2]t[3]t[4] !=t[0]t[1]t[2]
,但並不管
t[0]
和t[5]
相不相等。換句話說:就算
t[5]==』x』,
或t[5]==』y』,t[5]==』9』,
也有next[5]= 0 。
從這裡我們可以看到:串的模式值第一種表示方法能表示更多的資訊,第二種表示方法更單純,不容易搞錯。當然,用第一種表示方法寫出的模式匹配函式效率更高。比如說,在串s=「
adcadcbdadcadcad 9876543
」中匹配串t=「
adcadcad」,
用第一種表示方法寫出的模式匹配函式
,當比較到
s[6] != t[6]
時,取next[6]= -1
(表三)
,它可以表示這樣許多資訊:
s[3]s[4]s[5]==t[3]t[4]t[5]==t[0]t[1]t[2]
,而s[6] != t[6]
,t[6]==t[3]==t[0]
,所以s[6] != t[0],
接下來比較
s[7]
和t[0]
吧。如果用第二種表示方法寫出的模式匹配函式
,當比較到
s[6] != t[6]
時,取next[6]= 3
(表三)
,它只能表示:
s[3]s[4]s[5]== t[3]t[4]t[5]==t[0]t[1]t[2]
,但不能確定
t[6]
與t[3]
相不相等,所以,接下來比較
s[6]
和t[3];
又不相等,取
next[3]= 0
,它表示
s[3]s[4]s[5]== t[0]t[1]t[2]
,但不會確定
t[3]
與t[0]
相不相等,即
s[6]
和t[0]
相不相等,所以接下來比較
s[6]
和t[0]
,確定它們不相等,然後才會比較
s[7]
和t[0]
。是不是比用第一種表示方法寫出的模式匹配函式多繞了幾個彎。
為什麼,在講明第一種表示方法後,還要講沒有第一種表示方法好的第二種表示方法?原因是:最開始,我看嚴蔚敏的乙個講座,她給出的模式值表示方法是我這裡的第二種表示方法,如圖:
她說:「
next
函式值的含義是:當出現
s[i] !=t[j]
時,下一次的比較應該在
s[i]
和t[next[j]]
之間進行。」雖簡潔,但不明了,反覆幾遍也沒明白為什麼。而她給出的演算法求出的模式值是我這裡說的第一種表示方法
next
值,就是前面的
get_nextval()
函式。匹配演算法也是有瑕疵的。於是我在這裡發帖說她錯了:
現在看來,她沒有錯,不過有張冠李戴之嫌。我不知道,是否有人第一次學到這裡,不參考其他資料和明白人講解的情況下,就能搞懂這個演算法(我的意思是不僅是演算法的大致思想,而是為什麼定義和例子中
next[j]=k(0
≤k,而演算法中
next[j]=k(-1
≤k)。憑良心說:光看這個講座,我就對這個教受十分敬佩,不僅講課講得好,聲音悅耳,而且這門課講得層次分明,恰到好處。在kmp這個問題上出了點小差錯,可能是編書的時候,在這本書上抄下了例子,在那本書上抄下了演算法,結果不怎麼對得上號。因為我沒找到原書,而據有的網友說,書上已不是這樣,也許吧。說起來,教授們研究的問題比這個高深不知多少倍,哪有時間推演這個小演算法呢。總之,瑕不掩玉。
書歸正傳,下面給出我寫的求
第二種表示方法表示的模式值的函式
,為了從
s的任何位置開始匹配
t,「當出現
s[i] !=t[j]
時,下一次的比較應該在
s[i]
和t[next[j]]
之間進行。」
定義next[0]=0 。
void myget_nextval(const char *t, int next) {
// 求模式串t的
next
函式值(第二種表示方法)並存入陣列
next。
int j = 1, k = 0;
next[0] = 0;
KMP字串模式匹配詳解 四
五 其他表示模式值的方法 上面那種串的模式值表示方法是最優秀的表示方法,從串的模式值我們可以得到很多資訊,以下稱為第一種表示方法。第二種表示方法,雖然也定義 next 0 1,但後面絕不會出現 1,除了 next 0 其他模式值 next j k 0 k的意義可以簡單看成是 下標為 j的字元的前面最...
KMP字串模式匹配詳解
kmp字串模式匹配詳解 kmp字串模式匹配通俗點說就是一種在乙個字串中定位另乙個串的高效演算法。簡單匹配演算法的時間複雜度為o m n kmp匹配演算法。可以證明它的時間複雜度為o m n 一.簡單匹配演算法 先來看乙個簡單匹配演算法的函式 int index bf char s char t in...
KMP字串模式匹配詳解
簡單匹配演算法的時間複雜度為o m n kmp匹配演算法時間複雜度為o m n 一 簡單匹配演算法 先來看乙個簡單匹配演算法的函式 int index bf char s char t int pos if else k next k while get nextval 另一種寫法,也差不多。voi...