1. 程式人生 > >KMP的next陣列求法詳解

KMP的next陣列求法詳解

近幾天學習kmp演算法,在next陣列求解上受苦頗深,看了不少部落格,感覺寫得都不夠清晰,所以想按照自己理解的過程來嘗試寫一下,也便於以後溫習。

關於kmp演算法的介紹,網上博文有很多,就不再贅述,推薦一篇kmp演算法,個人感覺挺好

這裡主要詳細講解next陣列的求解。
由於在下不擅作圖,有的地方單純用文字描述不夠清晰,還請原諒。
若有什麼地方寫得不對歡迎批評,以便於在下修正。

kmp演算法的精髓就在於next陣列,從而達到跳躍式匹配的高效模式
next陣列的值是代表著字串的字首與字尾相同的最大長度,(不能包括自身)

這裡舉個例子:

模式串t  A B A
B A A 下標 0 1 2 3 4 5 next 0 0 1 2 3 1 next[0]代表t[0]~t[0]即"A"的最大前後綴,顯然為0. next[1]代表t[0]~t[1]即"AB"的最大前後綴,為0. next[2]代表t[0]~t[2]即"ABA"的最大前後綴,即"A",長度為1. next[3]代表t[0]~t[3]即"ABAB"的最大前後綴,即"AB",長度為2. next[4]代表t[0]~t[4]即"ABABA"的最大前後綴,即"ABA",長度為3. next[5]代表t[0]~t[5]即"ABABAA"的最大前後綴,即"A",長度為1.

看到這裡,next值代表的意義應該可以明白了。
但next陣列怎樣用程式碼去求呢,我們當然不可能挨個去比較前後綴。
仍然是上面那個例子
A B A B A A
初始化,next[0]為0;
t[0] != t[1] next[1]為0;
t[0] == t[2] next[2]為1;
在求next[3]時,比較t[1]和t[3]是否相等?
相等:顯然 next[3] = next[2]+1;
不相等:怎麼辦? 看下面

void makeNext(char s[],int next[])
{
    int len = strlen(s);
    next[0]=0;                    //初始化
    for(int i=1,k=0;i<len;i++)
    {
        while(k>0 && s[k]!=s[i])  //這個while是最關鍵的部分
            k=next[k-1]; 
            //等價於  k=next[next[i-1]-1]
            //等號右邊的k起的只是下標的作用
        if
(s[k]==s[i]) k++; //相等就+1 next[i]=k; //賦值 } }

例子說話
A B A B A B A C
0 1 2 3 4 5 6 7
next[6] = 5
即字首為t[0]~t[4] 字尾為t[2]~t[6]
next[4] = 3
即字首為t[0]~t[2] 字尾為t[2]~t[4]
我們發現
next[4]的字首一定是next[6]的字首
next[4]的字尾也一定是next[6]的字尾
(這是while迴圈的原理,可以試著舉個例子驗證一下)

現在我們要求next[7],將t[7]與t[5] ( t[next[6]] )比較,發現不相等
那麼可以將t[7]與t[3] (t[ next[next[6]-1] ])比較,如果相等,則next[7] = next[4] +1 ;
不相等就重複此過程,直到t[7]與t[0]比較.

上框內過程其實就是程式碼中,while迴圈裡的內容,現在回過頭去看上面程式碼應該會順暢很多。

下面附上kmp完整程式碼

/*************************************************************************
    > File Name: kmp.cpp
    > Author: 
    > Mail:  [email protected]
    > Created Time: 2015年10月12日 星期一 18時32分00秒
 ************************************************************************/

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

using namespace std;

void makeNext(char s[],int next[])
{
    int len = strlen(s);
    next[0]=0;
    for(int i=1,k=0;i<len;i++)
    {
        while(k>0 && s[k]!=s[i])
            k=next[k-1];
        if(s[k]==s[i])
            k++;
        next[i]=k;
    }
}

int kmp(char t[],char s[])
{
    int len1 = strlen(t);
    int len2 = strlen(s);
    int next[len2];
    makeNext(s,next);
    for(int i=0,j=0;i<len1;i++)
    {
        while(j>0 && t[i]!=s[j])
        {
            j=next[j-1];
        }
        if(t[i]==s[j])
            j++;
        if(j==len2)
            return i-j+1;
    }
}

int main()
{
    char t[]="1234561123458412";
    char s[]="611";
    cout<<t<<endl;
    cout<<s<<endl;
    cout<<"下標為"<<kmp(t,s)<<endl;
}

相關推薦

KMP的next陣列求法

近幾天學習kmp演算法,在next陣列求解上受苦頗深,看了不少部落格,感覺寫得都不夠清晰,所以想按照自己理解的過程來嘗試寫一下,也便於以後溫習。 關於kmp演算法的介紹,網上博文有很多,就不再贅述,推薦一篇kmp演算法,個人感覺挺好 這裡主要詳細講解next

liunx磁盤陣列raid

liunx raid 一丶raid 1.raid定義 磁盤陣列(Redundant Arrays of Independent Disks,RAID),有“獨立磁盤構成的具有冗余能力的陣列”之意。磁盤陣列是由很多價格較便宜的磁盤,組合成一個容量巨大的磁盤組,利用個別磁盤提供數據所產生加成效果提升整個磁

JS中陣列方法

JS中陣列的方法有很多,但是自己一直沒有抽時間進行整理分類,故單獨寫一篇博文,對目前我所掌握的JS中陣列相關的方法進行整理,夯實一下自己的基礎。 我將陣列相關的方法分為兩類 1.方法會改變原陣列 相應的方法有:shift、unshift、pop、push、rev

Javascript 陣列語法

JavaScript 中的陣列相當於 Java 中的 Map ,陣列本身是一個物件,屬於引用資料型別 更多精彩 更多技術部落格,請移步 asing1elife’s blog 定義 既然陣列是一個物件,當進行 alert(arr) 時

Linux系統常用磁碟陣列RAID5

RAID5最少由3塊硬碟組成,每個硬碟容量一樣,資料儲存於磁碟陣列中的每個硬碟,其中一塊硬碟儲存資料校驗位,當丟失其中的一位時,RAID5能通過演算法,利用其他兩位資料將丟失的資料進行計算還原,因此RAID5最多隻能允許一塊硬碟損壞,可見磁碟利用率是(N-1)/N,資料的安全性得以保障,一般大多數人選擇用RA

RAID-磁碟陣列簡單

歷史來源 1988 年美國加州大學伯克利分校的 D. A. Patterson 教授等首次在論文 “A Case of Redundant Array of Inexpensive Disks” 中提出了 RAID 概念 ,即廉價冗餘磁碟陣列( Redunda

動態陣列vector(Java和C++)

1.概念描述: vector名為動態陣列 有些時候想開一個數組,但是卻不知道應該開多大長度的數組合適,因為我們需要用到的陣列很可能會根據情況變動。這時候我們就需要用到動態陣列。所謂動態陣列,也就是不定

C99可變長陣列VLA

C90及C++的陣列物件定義是靜態聯編的,在編譯期就必須給定物件的完整資訊。但在程式設計過程中,我們常常遇到需要根據上下文環境來定義陣列的情況,在執行期才能確知陣列的長度。對於這種情況,C90及C++沒有什麼很好的辦法去解決(STL的方法除外),只能在堆中建立一個記憶體映像與需求陣列一樣的替代品,這種替

指標與陣列概念、指標陣列陣列指標

指標與陣列 指標可以與變數結合,也可以與陣列結合使用。指標陣列和陣列指標是兩個截然不同的概念,指標陣列是一種陣列,該陣列存放的是一組變數的地址。陣列指標是一個指標,表示該指標是指向陣列的指標。 1.指向陣列元素的指標 int a[5]={1,2,3,4,5}; int *p=a; //

next陣列求解

next陣列的求解方法是: 第一位的next值為0,第二位的next值為1,後面求解每一位的next值時,根據前一位進行比較。首先將前一位與其next值對應的內容進行比較,如果相等,則該位的next值就是前一位的next值加上1;如果不等,向前繼續尋找n

【原創】C++ 動態陣列 vector

一、引入 引入:略 vector收錄在STL裡,是一種特殊的資料結構。它的中文名字叫做“動態陣列”或者“不定長陣列”,有時也被翻譯成“容器”。 說白了,vector就是一個功能強大的陣列。下面讓我

Python中三維陣列位置

圖示效果圖:   直接貼程式碼: def test3D():     import numpy as np     data_array = np.zeros((3, 5, 6), dtype=np.int)   &

"array"陣列容器

"array<>"陣列容器 詳解陣列容器, 是儲存陣列的容器, 是C型別陣列的擴充, 可以使用迭代器進行操作;例如"std::array<int, 5>", 需要注意的是, 如果

Leetcode 33 搜尋旋轉排序陣列 思路+反思總結 python實現

本人一直在努力地積累Leetcode上用Python實現的題,並且會盡力講清每道題的原理,絕不像其他某些部落格簡略地帶過。如果覺得講的清楚,歡迎關注。題目:假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5

2016多校訓練#5 1012 HDU 5792 樹狀陣列 程式碼

               World is Exploding Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s

二維陣列

二維陣列在概念上是二維的,有行和列,但在記憶體中所有的陣列元素都是連續排列的,它們之間沒有“縫隙”。 要用陣列指標來操作二維陣列。int (*p)[4]=a;  //p每移動一次就是移動了一個一維陣列。    指標陣列:int *p=a[4];            

樹狀陣列總結——(單點/區間查詢, 單點/區間修改, 逆序對)

2017-06-13 17:24 64人閱讀 評論(0)收藏舉報 1、概述   樹狀陣列(binary indexed tree),是一種設計新穎的陣列結構,它能夠高效地獲取陣列中連續n個數的和。概括說,樹狀陣列通常用於解決以下問題:陣列{a}中的元素可能不斷地被

磁碟陣列RAID

一、功能 1 對磁碟高速存取(提速) 2 擴容 3 資料冗餘 二、分類 RAID可分為級別0到級別6,通常稱為:RAID0,RAID1,RAID2,RAID3,RAID4,RAID5,RAID6。 RAID0:RAID0並不是真正的RAID結構,沒有資料冗餘,RAID0連續地分割資料並並行地讀/寫

C 語言中二維陣列指標

C語言中,指標是一個複雜但又靈活多變的知識點,我們知道,在一維陣列中,對於一個數組a[],*a,a,&a,都表示a的首地址,但如果與二維陣列混合使用,就顯得更為複雜了。例如對於一個二維陣列  a[2][4]={{1,2.3},{4,5,6}}  a+i,&a

C++中陣列引數

// 引數為10個int的陣列// parameter is a reference to an array of 10 intsvoid putValues(int (&arr)[10]);int main(){    int i, j[2];    int a[10];    putValue