邊城愚人

          如果我不在邊城,我一定是在前往邊城的路上。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            31 隨筆 :: 0 文章 :: 96 評論 :: 0 Trackbacks

          ??? ??? 設(shè)有主串s和子串t,子串t定位是指在主串s中找到一個與子串t相等的子串。通常把主串s稱為目標(biāo)串,把子串t稱為模式串,因此定位也稱作模式匹配。模式匹配成功是指在目標(biāo)串s中找到一個模式串t

          ??? ??? 傳統(tǒng)的字符串模式匹配算法(也就是BF算法)就是對于主串和模式串雙雙自左向右,一個一個字符比較,如果不匹配,主串和模式串的位置指針都要回溯。這樣的算法時間復(fù)雜度為Onm),其中nm分別為串s和串t的長度。

          ??? ??? KMP 算法是由KnuthMorrisPratt等人共同提出的,所以成為KnuthMorrisPratt算法,簡稱KMP算法。KMP算法是字符串模式匹配中的經(jīng)典算法。和BF算法相比,KMP算法的不同點是匹配過程中,主串的位置指針不會回溯,這樣的結(jié)果使得算法時間復(fù)雜度只為Onm)。下面說說KMP算法的原理。

          假設(shè)我們有個模式串為“abdabcde”存于數(shù)組t,我們要求的就是模式串的next值,見下表所示:


          i

          0

          1

          2

          3

          4

          5

          6

          7

          t[i]

          a

          b

          d

          a

          b

          c

          d

          e

          next[i]

          -1

          0

          0

          0

          1

          2

          0

          0

          ??? ??? 求模式tnext[i](稱為失效函數(shù))的公式如下:


          next[i] =Screenshot11.png

          ( 上面的公式中非t字母和數(shù)字組成的為數(shù)組下標(biāo))

          ??? ??? 應(yīng)該如何理解next數(shù)組呢?在匹配過程中,如果出現(xiàn)不匹配的情況(當(dāng)前模式串不匹配字符假定為t[i]),它所對應(yīng)的next[i]的數(shù)值為接下來要匹配的模式串的字符的索引;也就是說,出現(xiàn)不匹配的情況時,模式串的索引指針要回溯到中next[i]所對應(yīng)的位置,而主串的索引指針保持不變。

          ??? ??? 特別的,next數(shù)組中的next[0]next[1]的取值是固定的,為了標(biāo)識出首字母,需要假定next[0]為-1(取為-1是考慮到C語言中的數(shù)組索引以0開始)。在實現(xiàn)的時候,要實現(xiàn)公式中情況的處理需要些技巧,下面給出具體的實現(xiàn):

          # include?<stdio.h>
          #include?<stdlib.h>


          typedef?struct?QString?{
          ????char
          * ?cs;
          ????
          int ?len;
          }String;


          void?GetNext(String?s
          , int ? next []){
          ????
          int ?len? = ?s . len;
          ????
          int ?i? = ? 0 ;
          ????
          int ?k? = ? - 1 ;
          ????
          next [ 0 ]? = ? - 1 ;
          ????
          while (i? < ?len - 1 ){
          ????????
          if (k ==- 1 ? || ?s . cs[i]? == ?s . cs[k]){
          ????????????i
          ++ ;
          ????????????k
          ++ ;
          ????????????
          next [i]? = ?k;
          ????????}
          else {
          ????????????k?
          = ? next [k];
          ????????}
          ????}
          }


          int ?KMPIndex(String?s , String?m){
          ????
          int ? next [m . len] , i = 0 , j = 0 ;
          ????
          int ?k;
          ????GetNext(m
          , next );
          ??? while (i < s . len?? && j < m . len){
          ????????
          if (j ==- 1 ? || ?s . cs[i]? == ?m . cs[j]){
          ????????????i
          ++ ;
          ????????????j
          ++ ;
          ????????}
          else {
          ????????????j?
          = ? next [j];
          ????????}
          ????}
          ????
          if (j? >= ?m . len) return ?i - m . len;
          ????
          else ? return ? - 1 ;
          }


          ??? ??? KMP 算法也有需要改進的地方。對于模式串“aaaadd”在匹配時(假定被匹配串為“aaadddd”),可以看到,在匹配到索引3時,主串字符為“d”,模式串字符為“a”,如果按照上面的做法,這時模式串只會回溯一個索引,由于仍不匹配,模式串還會回溯一個索引,直到索引位置到了首字符,主串的索引指針才會前進一位,這樣就會浪費一些不必要的比較時間。出現(xiàn)這種情況的原因是模式串中位置i的字符與next[i]對應(yīng)的字符相同,需要修正next[i]next[i]對應(yīng)的字符的索引。下面列出“aaaadd”修正的nextval數(shù)組的內(nèi)容:

          i

          0

          1

          2

          3

          4

          5

          t[i]

          a

          a

          a

          a

          d

          d

          next[i]

          -1

          0

          1

          2

          3

          0

          nextval[i]

          -1

          -1

          -1

          -1

          0

          0

          ??? ??? 修正函數(shù)如下:

          void?GetNextval(String?s , int ?nextval[]){
          ????
          int ?len? = ?s . len , i? = ? 0 , k? = ? - 1 ;
          ????nextval[
          0 ]? = ? - 1 ;
          ????
          while (i? < ?len - 1 ){
          ????????
          if (k ==- 1 ? || ?s . cs[i]? == ?s . cs[k]){
          ????????????i
          ++ ;
          ????????????k
          ++ ;
          ????????????
          if (s . cs[i]? != ?s . cs[k]){
          ????????????????nextval[i]?
          = ?k;
          ????????????}
          else ???nextval[i]? = ??nextval[k];????????????
          ????????}
          else {
          ????????????k?
          = ?nextval[k];
          ????????}
          ????}
          }

          ??? ??? 注:以上函數(shù)在gcc4.1下編譯運行通過,使用C而不是java的原因主要希望借此熟悉一下學(xué)過的語言。以上內(nèi)容絕大部分為《數(shù)據(jù)結(jié)構(gòu)習(xí)題與解析》一書中的相關(guān)內(nèi)容,我只是費勁將其敲打出來。實話實說,我覺得自己并沒有寫明白這個算法,如果給出一個具體的匹配過程會更好,但寫起來就要麻煩許多。對未讀懂此文的朋友表示歉意。

          posted on 2007-06-17 22:14 kafka0102 閱讀(9689) 評論(6)  編輯  收藏 所屬分類: DS&Algorithms

          評論

          # re: 數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之字符串模式匹配KMP算法 2007-10-02 17:55 halftomato
          如果我不在變成,那我一定是在前往邊城的路上。
          很喜歡這句話。與君共勉。  回復(fù)  更多評論
            

          # re: 數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之字符串模式匹配KMP算法 2007-10-02 17:56 halftomato
          如果我不在邊城,那我一定是在前往邊城的路上。
          很喜歡這句話。與君共勉。  回復(fù)  更多評論
            

          # re: 數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之字符串模式匹配KMP算法 2008-01-02 14:18 feather
          寫的不錯,就是如何生成next寫的不清楚啊,來看文章的一般都是對next生成的原理覺得有疑問的。  回復(fù)  更多評論
            

          # re: 數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之字符串模式匹配KMP算法[未登錄] 2008-08-16 14:57 小春
          還是不太理解next()  回復(fù)  更多評論
            

          # re: 數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之字符串模式匹配KMP算法 2008-10-18 00:28 konk
          拿本數(shù)據(jù)結(jié)構(gòu)的書,對這看兩個小時就會懂了  回復(fù)  更多評論
            

          # re: 數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之字符串模式匹配KMP算法 2009-01-06 11:57 xxxx
          aaaadd的nextval 分別為-1 -1 -1 -1 3 0

          模式串a(chǎn)aaadd 母串a(chǎn)aaaadd
          按照你上面標(biāo)的nextval -1 -1 -1 -1 0 0就找不到字串了

          不過修正算法是對的  回復(fù)  更多評論
            

          主站蜘蛛池模板: 阳谷县| 德钦县| 辽阳县| 盐边县| 虎林市| 米脂县| 宜章县| 大余县| 磴口县| 苏尼特左旗| 方正县| 原平市| 南川市| 文成县| 遂川县| 博野县| 三穗县| 兴国县| 会泽县| 平顺县| 黎川县| 吉木乃县| 锡林浩特市| 岢岚县| 宜春市| 营山县| 锦屏县| 甘德县| 宜君县| 静宁县| 美姑县| 弥渡县| 惠州市| 普格县| 扶沟县| 南城县| 保亭| 合作市| 惠州市| 承德市| 雷山县|