1. 程式人生 > >資料結構---串的模式匹配演算法介紹

資料結構---串的模式匹配演算法介紹

前言
The years teach much which the days never knew.
Time:2017/2/19
Name:Willam

1、介紹
對於文字程式來說,找出一個子串在文字中的位置是特別重要的,我們稱那個子串為模式串(pattern),然後我們稱尋找的過程為:模式匹配(string match)。

2、實現演算法(1)—樸素字串匹配演算法

原理:從主串的指定的起始位置字元開始和模式第一個字元比較,如果相等,則繼續比較下一個字元,如果不等,則從主串的下一個字元開始和模式的第一個字元開始比較,以此類推,直到模式串所有字元都匹配完成,則匹配成功,否則,匹配不成功。

程式碼實現


//pos是從1開始的一個下標
int index_force(char * s, char * t,int pos)
{

    int i=pos-1;
    //判斷pos是否合法
    if(!s[i])
    cout<<"起始位置不合法"<<endl;
    int j=0;
    while(s[i]!='\0' && t[j]!='\0')//主串或者模式串遍歷完成
    {
        if(s[i]==t[j])//如果主串和模式串對應位置的值相等,則比較後面的字元
        {
            ++i;
            ++j;
        }
        else
//如果不相等,則模式串需要回朔到第一個字元,而主串則從下一個字元開始 { i=i-j+1; j=0; } } if(t[j]=='\0')//如果迴圈是由於模式串遍歷完了而結束的,說明找到了對應子串的位置 { return i-j+1; } else //否則,主串不包含模式串 { return 0; } }

時間複雜度的分析:我們這裡只分析最壞的情況,那就是對於長度為n的模式串和長度為m的主串,模式串前n-1都是同樣的字元而且主串的前m-1也是和模式串一樣的字元,例如:模式串為:000001,主串為:000000000000000000000001,則對於這種情況的時間複雜度為:其中我們需要回朔:m-n+1次,每次都要比較:n次,所以我們的時間複雜度為:o((m-n+1)n)

3、實現演算法(2)—-KMP演算法的實現
簡介:KMP演算法它是有Knuth、Morris和Pratt三個人同時發現的,所以我們稱之為KMP演算法。它是一個很優秀的演算法,通過對模式串的一個預處理,將我們的時間複雜度減少到了一個線性的水平。

剖析演算法的原理:
下面我們將在實際的應用中來解釋這個演算法,首先我們有主串:acabaabaabcacaabc,有模式串:abaabcac,現在假設我們匹配到了如下的圖的步驟:
這裡寫圖片描述
現在模式串的第六個字元和主串匹配不上了,那麼現在我們就需要把模式串往右移動,並且重新選擇主串和模式串的比較位置重新開始比較。那麼如果是樸素法的話,我們是直接把模式串往右移動一格,然後,主串的第四個字元和我們模式串的第一個字元重新開始做比較。但是,你要知道其實主串的第三個字元到第六個字元我們都是已經和模式串做過比較的,而且我們知道他們的各個位置上的內容是什麼,那麼為什麼不把這些已經知道的資訊充分利用起來了?比如:我們知道模式串中紅色的兩個字元和綠色的兩個字元是相等的,而且紅色的兩個字元正好是模式串開始的兩個字元,所以我們可以直接把模式串向右移動四位,然後,我們主串從剛才發現不匹配那個字元位置開始和模式串的第三個位置比較,這樣我們就可以減少五次比較。
哇噻,就是一個簡單的處理,就給我們的程式效率帶來了質的飛越,那麼現在程式的最要緊要解決的問題就是我們主串比較位置不做任何改動,那麼我們怎麼知道該從模式串的哪個位置開始做比較了,這個時候,我們就需要對我們的模式串做一個預處理,通過預處理我們可得到一個next陣列,它儲存的就是當我們在模式串某個位置匹配失敗後,應該從模式串的哪個位置重新開始比較。要求得next陣列,那麼我們就要理解剛才的那個例子為什麼可以從模式串的第三個位置重新開始比較。其實next陣列就是說對於模式串j這個位置之前(1到j-1)的串中,是否存在從模式串第一個位置出發往右移動得到的子串從模式串的第j-1個字元位置出發往左移動得到的子串匹配,而且當該串達到最大長度時,則next值就是該串的長度加一,例如:abaabc這個模式串中,在c這個位置之前存在一個最大子串:ab。然後,我們next值就是記錄這個最大子串的下一個字元的位置,其實說到這裡,我們也就理解到了為什麼要第三個字元了,因為模式串的前兩個字元已經和主串匹配成功了(生成next值的時候,就完成了這個任務),所以不用再比較了。
程式碼實現:
get_next函式的實現

//next函式的實現,
void get_next(char * s,int * next)
{
    int i=0;  //next陣列的下標
    int j=-1;  //next值
    next[0]=-1;
    while(s[i]!='\0')
    {
        if(j==-1 || s[i]==s[j]) //如果不存在或這條件符合了,那麼就可以得到next值了
        {
            ++i;++j;
            next[i]=j;
        }
        else{
            j=next[j];
        }
    }
}

KMP函式的實現:

//KMP演算法的實現
int KMP(char * s,char * t,int pos)
{

    int j=0;
    while(t[j++]!='\0');
    int * next=new int[j-1];

    int length=j-1; //串的長度
    //呼叫函式,生成對應的next值
    get_next(t,next);

    int i=pos-1;//主串的起始位置
    j=0;//模式串的下標
    while(s[i]!='\0' && j<length)
    {
        if(j==-1 || s[i]==t[j]) //考慮到第一個不相等的情況
        {
            ++i;++j;
        }
        else
        {
            j=next[j];  //如果不相等,則從next值開始下一次比較(模式串的右移)
        }
    }

    if(t[j]=='\0' && j!=-1)
    {
        return i-j+1;
    }
    else
    {
        return 0;
    }
}

演算法的改進:
其實我們的next函式還是有一點缺陷,我們還可以通過一定的改進,讓我們的演算法的得到進一步的優化,例如:當我們的模式串為:ooooa,主串為:ooocooooa,我們根據之前的next函式可以得到next陣列的值為:-10123,所以當我們的模式串的第四個字元和主串的第四個字元發生不相等的時候,我們還需要額外的三次比較,才知道這個我們應該直接把主串往前移動一位,後繼續比較。其實,我們完全可以在生成next值的時候,避免這種情況出現,程式碼修改如下:

//next函式的實現,
void get_next(char * s,int * next)
{
    int i=0;  //next陣列的下標
    int j=-1;  //nextnext[0]=-1;
    while(s[i]!='\0')
    {
        if(j==-1 || s[i]==s[j]) //如果不存在或這條件符合了,那麼就可以得到next值了
        {
            ++i;++j;
            //修改程式碼部分
            if(s[i]!=s[j])//只有兩者不相等的時候,才需要更換nextnext[i]=j;
            else
            next[i]=next[j];
        }
        else{
            j=next[j];
        }
    }
}

時間複雜度的分析:KMP演算法就有兩個步驟:第一個就是花費:O(m)的時間去對模式串進行預處理,其中m為模式串的長度,另外一個就是遍歷主串,最壞的情況就是:O(n),其中n為主串的長度,所以KMP的時間複雜度為:O(m+n)

4、實現演算法(4)—Horspool演算法
簡介:Horspool演算法是一個基於字尾匹配的一種模式匹配演算法,它算是匹配演算法中的一種的新的創新,因為我們在匹配模式串的時候,都是從左向右匹配的,但是Horspool卻是從右向左匹配,其實它的這種思路我們也是知道的:那就為了讓模式串可以儘可能的向右移動的距離長一點,這樣我們的匹配演算法的效率才會提高,那麼字尾匹配的方法到底有什麼好處了,通過下面這幅圖,你就明白了
這裡寫圖片描述
我們如果從模式串的最後一個字元開始比較,那麼當第一個字元不可以的時候,我們可以馬上停止比較其他字元,從而節省多次比較。當然,我們怎麼知道我們需要把模式串往右移動多少位了,那麼這個正是Horspool演算法要做的事情

演算法原理的剖析
模式串從右向左進行匹配。對於每個文字搜尋視窗(其實就是主串中一個和模式串長度相等的子串,我們稱之位一個文字搜尋視窗),將視窗內的最後一個字元與模式串的最後一個字元進行比較。如果相等,則繼續從後向前驗證其他字元,直到完全相等或者某個字元不匹配。然後,無論匹配與否,都將根據在模式串的下一個出現位置將視窗向右移動。模式串與文字串列埠匹配時,模式串的整體挪動,是從左往右,但是,每次挪動後,從模式串的最後一個字元從右往左進行匹配。,演算法的解釋可能太過抽象,那麼下面我們直接看一個示例:其中我們的主串是:abcbcsdcodecbcac,模式串是:cbcac

模擬Horspool演算法模式匹配的過程:
(1)第一步
這裡寫圖片描述
首先,我們從對主串和模式串從左向右進行匹配,發現模式串的第四個字元(a)和主串的字元(b)不匹配,那麼這個時候我們就要移動模式串,我們需要從模式串的右邊向左尋找。模式串是否有字元(b),我們就在模式串的第二個位置找到了,所以我們就需要把模式串的b和主串上的b對齊,換句話說,就是模式串需要往右移動兩位(3-1,其中3是不匹配時,模式串中字元的下標,另外一個就是b在模式串中的下標,下標是從0開始)

(2)第二步
這裡寫圖片描述
現在,我們繼續從右向左比較模式串和主串的值,然後,我們發現第一個字元就不匹配了,其中,主串不匹配的字元為:d,然後,從右向左在模式串中尋找d,最後發現,模式串中沒有d,那麼我們直接把模式串整體往右移動到其第一個字元和主串剛剛那個不匹配字元d的下一個字元(c)對齊,其中,模式串整體往右移動了5個位置(4-(-1)=5,其中4是模式串不匹配時,模式串值中那個字元的下標,因為d不存在於模式串中,所以我們尋找到的下標為:-1)

(3)第三步
這裡寫圖片描述
我們重複第二步的步驟,因為e同樣不在模式串中。
(4)第四步
這裡寫圖片描述
好了,經過了四個步驟,我們終於匹配成功,通過了這個例子我們應該已經知道了Horspool演算法的原理了,並且程式碼實現,應該也很容易了。
我們得到的規則只有一條,即:

                    **字串後移位數=失配字元位置-失配字元上一次出現的位置**

如果失配字元根本就沒有出現在模式串中,我們將“失配字元上一次出現的位置”的值視為-1。

程式碼實現:

//Horspool函式的實現
int Horspool(char * source,char * pattern)
{
    int source_length=strlen(source);
    int pattern_length=strlen(pattern);
    int i=0;    //主串的下標的移動
    int j=0;    //模式串的下標
    int k=0;     
    char misch;  //記錄未匹配成功時,主串上的字元
    int mis_dis=0;
    for(i=0;i<=source_length-pattern_length;)//注意終止條件,就是當剩餘的串已經不夠長時,就可以終止了
    {
        for(j=pattern_length-1;j>=0;--j)
        {
            if(source[i+j]!=pattern[j])
            {
                misch=source[i+j];
                mis_dis=j;
                break;          
            }
            if(j==0)
            return i+1;
        }
        //尋找模式串中是否有未匹配的字元
        for(k=mis_dis-1;k>=0;--k)
        {
            if(pattern[k]==misch)
            {
                i+=(mis_dis-k);
                cout<<"i="<<i<<endl;break;
            }       
              if(k==0)//不存在的時候
            {
                i+=(mis_dis+1);
                cout<<"i="<<i<<endl;
            }
        }
    }
    return 0;

}   

5、實現演算法(3)—-BM演算法

簡介:BM演算法是在1977年由Robert S.Boyer和J Strother Moore提出的一個基於字尾匹配的模式匹配演算法,它的匹配速度比KMP都還快4-5倍,而且在絕大多數的場合下的應用效能極嘉,比如我們經常使用的Ctrl+F就是通過這個演算法實現模式匹配的。

演算法原理的剖析

BM演算法效能之所以可以比KMP演算法好,第一個原因就是它使用了字尾匹配的模式匹配演算法(這裡在Horspool裡解釋了原因),另外,一個就是它對當模式串出現不匹配的情況時,採取兩種方式並行移動模式串的演算法,其中一種叫:壞字元規則,還有一種叫做:好字尾規則。

好了,在介紹什麼是壞字元規則和好字尾規則之前,我們先來看看什麼是壞字元和好字尾。如下圖所示:
這裡寫圖片描述

如上圖,第一行就是主串,第二行為模式串,當模式串匹配到紅線的時候,發現和主串的字元不匹配了,那麼主串的字元:“I”,就是壞字元,而模式串的字串:“MPLE ”,這個字串我們叫好字尾。

開心,現在我們都明白什麼是壞字元和好字尾了。下面我就先給大家介紹什麼是壞字元規則。其實,我們所說的規則都是在模式匹配失敗的時候,計算我們模式串需要移動的距離,這樣我們才可以在一個新的位置重新進行模式匹配,在壞字元規則下,模式串移動有兩種情況:

  • 壞字元沒出現在模式串中,這時可以把模式串移動到壞字元的下一個字元,繼續比較,如下圖:
    這裡寫圖片描述
  • 壞字元出現在模式串中,這時可以把模式串最右邊第一個出現的壞字元和主串的壞字元對齊,當然,這樣可能造成模式串倒退移動(這個情況的出現也是我們需要好字尾規則的一個原因),如下圖:
    這裡寫圖片描述

好了,到這裡我們可以先用程式碼把壞字元規則實現,其實,我們先按照ASCII編碼的規則,來實現我們的壞字元,因為,我們從上面的兩種情況可以知道,其實如果某個字元不在模式串中,那麼這個時候,模式串需要往右移動距離為模式串的長度,所以我們可以宣告一個大小為256的陣列,記錄每個ASCII值在字元不匹配時,壞字元時該ASCII值時,模式串需要移動的距離。

/*//Bc函式的實現,因為我們是按照ASCII編碼規則進行程式碼設計的,所以我們開始就申請256個空間
//  第一個for迴圈處理上述的第一種情況,這種情況比較容易理解就不多提了。
//  第二個for迴圈,Bc_table[s[j]中s[i]表示模式串中的第i個字元。
//  Bc_table[s[j]]=len-j-1;也就是計算s[i]這個字元到串尾部的距離。
//  為什麼第二個for迴圈中,i從小到大的順序計算呢?哈哈,技巧就在這兒了,原因在於就可以在同一字元多次出現的時候以最靠右的那個字元到尾部距離為最終的距離。當然了,如果沒在模式串中出現的字元,其距離就是len了。
*/
void Bc(char * s,int * Bc_table)
{
    int len=strlen(s);
    int i=0;
    for(i=0;i<256;i++)
    {
        *(Bc_table+i)=len;  //先把對映表的距離全部初始化為模式串的長度
    }
    int j=0;
    for(j=0;j<len-1;++j)
    {
        Bc_table[s[j]]=len-j-1;//記錄模式串中,每個字元最靠右那個字元的位置
    }
}

下面,我們再看看什麼是好字尾規則,好的字尾規則同樣是會有三種情況出現:

  • 模式串中有子串匹配上好字尾,此時移動模式串,讓該子串和好字尾對齊即可,如果超過一個子串匹配上好字尾,則選擇最靠左邊的子串對齊。
    這裡寫圖片描述
  • 模式串中沒有子串匹配上後後綴,此時需要尋找模式串的一個最長字首,並讓該字首等於好字尾的字尾,尋找到該字首後,讓該字首和好字尾對齊即可。
    這裡寫圖片描述
  • 模式串中沒有子串匹配上後後綴,並且在模式串中找不到最長字首,讓該字首等於好字尾的字尾。此時,直接移動模式到好字尾的下一個字元。
    這裡寫圖片描述

通過,上述的三種情況,為了實現好字尾規則,需要定義一個數組suffix[],其中suffix[i] = reslut 表示以i為邊界,與模式串字尾匹配的最大長度,如下圖所示,用公式可以描述:滿足P[i-s, i] == P[len-result, len]的最大長度reslut。記住:我們需要匹配的是模式串的字尾表示式,所以每次得到了模式串某個位置的最長字尾表示式的長度之後,下一個位置又是和我們的模式串的最後一個字元開始比較。

下面就是我們得到suffix陣列的函式

void get_suffix(char * s,int * suffix)
{
    int i=0;
    int j=0;
    int k=0;
    int result;
    int len=strlen(s);  //模式串的長度
    suffix[len-1]=len;  //模式串最後一個字元是一個特例,它是一個完全模式串字尾,所以長度就是模式串的長度
    for(i=len-2;i>=0;--i)  //從模式串的倒數第二個字元開始迴圈,求suffix的值
    {
        k=i;   //我們想要尋找的那個子串的第一個字元
        j=len-1; //模式串的最後一個字元
        result=0; //記錄那個子串的長度
        while(s[k--]==s[j--]) //開始往前比較
        {
            ++result;
        }
        suffix[i]=result; //得到最大模式串的字尾的長度
    }
}

好了,現在有了suffix,我們就要開始進行我們的好字尾規則的實現了,其實,它同樣是得到一個數組,這個陣列記錄每次我們遇到了不匹配字元時,在該字元所在的位置上,以好字尾的規則,模式串需要移動的距離。在生成這個距離的時候,我們我們同樣是要對好字尾可能出現的三種情況進行考慮,

  • 模式串中沒有子串匹配上好字尾,但找不到一個最大字首
    這個時候,模式串需要移動的距離就是模式串的長度,這也是我們預設的移動距離,所以,程式一開始就可以把陣列初始化為模式串的長度

  • 模式串中沒有子串匹配上好字尾,但找到一個最大字首
    這裡寫圖片描述

  • 模式串中有子串匹配上好字尾
    這裡寫圖片描述

通過,這裡分析的三種情況,我們可以編寫出如下程式碼:

//Gs對映表的求解函式,
void Gs(char *s ,int * Gs_table)
{
    int len= strlen(s);
    int i;
    int * suffix=new int[len];
    //生成suffix陣列
    get_suffix(s,suffix);
    for(i=0;i<len;i++)
    {
        Gs_table[i]=len;  //先把所有的移動距離初始化為模式串的長度
    }
    int j=0;
    //第二種情況
    for(i=len-2;i>=0;--i)
    {
        if(suffix[i]==i+1)//x[i+1-suff[i]…i]==x[m-1-siff[i]…m-1],而suff[i]==i+1,我們知道x[i+1-suff[i]…i]=x[0,i],也就是字首,滿足第二種情況。
        {
            for(;j<len-1-i;++j)  //
            {
                if(Gs_table[j]==len)//保證只被修改一次
                {
                    Gs_table[j]=len-1-i;
                }
            }
        }
    }
    for(i=0;i<=len-2;++i)   //對應於第三種情況,結合著前面圖來理解程式碼
        Gs_table[len-1-suffix[i]]=len-1-i;
}

在這裡,仔細去分析和感受一下,Gs函式的編寫是有很多技巧在裡面的,首先我們要先有個概念就是:當我們按照好字尾規則移動的時候,如果模式串的一個字元位置同時符合剛剛分析的三種情況中的幾種,所以我們要選擇其中移動距離最小的那一種,這樣才可以保證不會出現匹配遺漏,通過分析,我們發現上述的三種情況中,其中第一種情況的移動距離最大,所以最先考慮,第二種為第二,第三種移動距離最小。
我們先是假設模式串每個字元都是符合第一種情況,就是沒有最大字首也沒有匹配的模式串字尾,其實就是把整個陣列初始化為模式串的長度。然後,我們再考慮第二種情況,我們從下面幾個問題來分析第二種情況
1. 為什麼從後往前,也就是i從大到小?     
原因在於如果i,j(i>j)位置同時滿足第二種情況,那麼m-1-i

int BM(char * s,char * t)
{
    int i=0;
    int j=0;
    int length_s=strlen(s);  //主串的長度
    int length_t=strlen(t);  //模式串的長度
    int * B=new int[256];
    int * G=new int[length_t];
    Bc(t,B);
    Gs(t,G);
    while(j<=length_s-length_t)
    {
        for(i=length_t-1;i>=0 && s[i+j]==t[i];--i);//往前匹配
        if(i<0)
        {   
            return j+1;
        }
        else
        {
            int g=G[i];
            int b=B[s[i+j]]-length_t+1+i;
            //選擇最大的值
            if(g>=b)
                j+=g;
            else
                j+=b;

        }
    }
    return 0;
}

好了,到現在,BM演算法實現完成。

6、總結
哎哎,本來昨晚就寫好的了,但是今天由於CSDN的bug,讓我的部落格變的不完整,從BM演算法那裡,我又重新寫了一遍,算是因禍得福吧,通過這次的編寫,我發現我對BM演算法的原理更加明清了,打算,去看看原論文,看看是不是和我的理解一樣。

相關推薦

資料結構---模式匹配演算法介紹

前言 The years teach much which the days never knew. Time:2017/2/19 Name:Willam 1、介紹 對於文字程式來說,找出一個子串在文字中的位置是特別重要的,我們稱那個子串為模式

演算法資料結構專場】BitMap演算法介紹

我們先來看個簡單的問題。假如給你20億個非負數的int型整數,然後再給你一個非負數的int型整數 t ,讓你判斷t是否存在於這20億數中,你會怎麼做呢?有人可能會用一個int陣列,然後把20億個數給存進去,然後再迴圈遍歷一下就可以了。想一下,這樣的話,時間複雜度是O(n),所需要的記憶體空間4byte *

資料結構 — 3.模式匹配

【問題描述】試編寫一個演算法,識別依次讀入的一個以@為結束符的字元序列是否為形如"序列1&序列2"模式的字元序 列. 其中序列1和序列2中都不含字元'&',且序列2是序列1的逆序.例

資料結構- 模式匹配演算法 BF和 KMP演算法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

資料結構- 模式匹配演算法: KMP演算法

1、KMP演算法求解什麼型別問題? 字串匹配。給你兩個字串,尋找其中一個字串是否包含另一個字串,如果包含,返回包含的起始位置。 2、完整的KMP演算法 #include <bits/stdc++

資料結構——模式匹配演算法

2、串的模式匹配演算法        串的查詢操作也稱作串的模式匹配操作,模式匹配操作的具體含義是:在主串(也稱作目標串)中,從位置start開始查詢是否存在子串(也稱作模式串),如在主串中查詢到一個與模式串相同的子串,則稱查詢成功;如在主串中為

資料結構——的樸素模式和KMP匹配演算法

一、樸素模式假設我們要從主串S=”goodgoogle"中找到子串T=“google"的位置,步驟如下:i表示主串的當前位置下標,j表示子串的當前位置下標,如上圖在第一輪比較(i=1開始)中j=4和i=4的位置不匹配,接下來就要指標回退,從i=2開始比較,如下:如此反覆直到比

資料結構——模式匹配演算法

        要找到模式串在主串中的位置,最簡單的方法就是一位一位的排查,如果相同,則比較下一項是否相同,一旦出現不同的字元,將剛剛匹配模式串主串的第一位向後移動一位繼續比較,這樣的演算法在某些串中可能會出現多次回溯,所以針對模式串的特點出現了一種改進——演算法KMP演算

資料結構 順序的各種模式匹配演算法

如圖效果: #include <iostream> #include<stdio.h> #include<string.h> using namespace std; #define MaxSize 100 int next[MaxSi

[從今天開始修煉資料結構]、KMP模式匹配演算法

[從今天開始修煉資料結構]基本概念 [從今天開始修煉資料結構]線性表及其實現以及實現有Itertor的ArrayList和LinkedList [從今天開始修煉資料結構]棧、斐波那契數列、逆波蘭四則運算的實現 [從今天開始修煉資料結構]佇列、迴圈佇列、PriorityQueue的原理及實現 一、什麼是串?  

C/C++/Java程式碼 樸素的(暴力法)模式匹配演算法 KMP演算法 資料結構

樸素的模式匹配(暴力法)演算法 演算法思想: 從目標串的的第一個字元起與模式串的第一個字元比較,若相等,則繼續對字元進行後續的比較,否則目標串從第二個字元起與模式串的第一個字元重新比較,直至模式串中的每個字元依次和目標串中的一個連續的字元序列相等為止,此時稱為匹配

的樸素演算法和KMP模式匹配演算法

串的樸素演算法和KMP模式匹配演算法   串的樸素演算法 (BF演算法又稱暴力搜尋):首先待匹配串與模式串首先左對齊,然後從左向右開始逐個進行匹配,如果出現失配情況,則從待匹配串下一個字元開始進行匹配,直到模式串匹配成功。   例如:   &nb

資料結構-- BF(樸素)演算法

時間複雜度: O(nm) ; 需求:解決字串主串是否包含子串的問題; 思路:採用雙指標;主串i 字串 j 當i與j相同時 i++,j++,如不同,j=0; i回退上次開始比較的的位置+1 匹配成功返回第一個字元的下標; class BF{ public sta

-模式匹配-MP演算法

之前學習了KMP演算法,現在學習一下它的弱化版:MP演算法。 為啥還要學習它呢?因為它是接下來要學習的AC-自動機的基礎。 輸入:主串S,子串T 輸出:主串中子串第一次出現的位置(0-length(S-1))。匹配不到不輸出. 樣例: S:ababcabcacbab

【筆記】模式匹配演算法

  串的模式匹配也稱為子串的定位操作,即查詢子串在主串中出現的位置。設有主串S和子串T,如果在主串S中找到一個與子串T相相等的串,則返回串T的第一個字元在串S中的位置。其中,主串S又稱為目標串,子串T又稱為模式串。本文主要介紹兩種常用的模式匹配演算法,即樸

淺談單模式字串匹配演算法(KMP)

字串演算法很有趣,尤其是KMP和AC自動機~~ 大綱 1.問題定義 字串匹配是電腦科學中最古老、研究最廣泛的問題之一。一個字串是一個定義在有限字母表∑上的字元序列。例如,ATCTAGAGA是字母表∑ = {A,C,G,T}上的一個字串。字串匹配問題就是在一個大的字串

-樸素的模式匹配演算法(java)

樸素的模式匹配演算法實現Java中indexOf(String str, int fromIndex); 即字主字串中查詢目標字串並返回指標地址; public class StringUtils { public static int inde

(2)--模式匹配演算法

演算法目的:確定子串在主串中第一次出現的位置 兩種演算法:BF,KMP(重點掌握) 一:BF演算法 1.特點:主串的指標需回溯,速度慢; 2.演算法思想:        當主串T(長為m)和子串S(長為n)的比較字元不相等時,主串的指標i需要指向之前開始比較的位置的後面一個

模式匹配演算法(BF演算法和KMP演算法

串的模式匹配演算法 子串的定位操作通常稱為串的 模式匹配,其中T稱為 模式串。 一般的求子串位置的定位函式(Brute Force) 我寫java的程式碼是這樣的 int index(String S,String T,int pos){

模式匹配演算法---BF、KMP

尋找字串S中字串T出現的位置或者次數的問題屬於字串匹配問題。 BF演算法: eg: 主串:s="ababcabcacbab"; 模式串:t="abc"; 1.變數i,j(初始值為0、1都行)分別指向S、T的第一個位置(這裡是指i=1;j=1(i=0;j=0))。 2.