【啊哈,算法】之八、串和kmp算法

来源:互联网 发布:python 培训 郑州 编辑:程序博客网 时间:2024/06/03 17:31

字符串大家应该不陌生了!

个人代码积累:

先来看看串的结构定义:

#include<iostream>using namespace std;typedef char Type;#define MAXSIZE 100typedef struct String{Type data[MAXSIZE];int length;}String;

串有许多操作,如:初始化,创建串,清空串,插入,复制,比较,链接,寻找字串,寻找串的位置等:


void StrInsert(String *S, int pos, String T){if(S->length >= MAXSIZE){cout << "插入失败" << endl;return ;}int i = S->length - 1;int n = T.length;for(; i >= pos; --i){S->data[i+n] = S->data[i];}i++;for(int j = 0; j < n; j++){S->data[i++] = T.data[j];}S->length = S->length + T.length;}void InitString(String *S){for(int i = 0; i < MAXSIZE; ++i)S->data[i] = 0;S->length = 0;}void CreateString(String *S){Type e;int n;cout << "请输入元素个数:";cin >> n;S->length = n;int i = 0;while(n--){cout << "请输入数据:";cin >> e;S->data[i++] = e;}}void StrCopy(String *S, String T){for(int i = 0; i < T.length; i++){S->data[i + S->length] = T.data[i];}S->length = S->length + T.length;}void ClearString(String *S){InitString(S);}bool StringEmpty(String S){if(S.length == 0)return true;elsereturn false;}int StrLength(String S){return S.length;}int StrCompare(String S, String T){if(S.length > T.length)return 1;if(S.length < T.length)return -1;for(int i = 0; i < S.length; ++i){if(S.data[i] > T.data[i])return 1;if(S.data[i] < T.data[i])return -1;}return 0;}void StrCat(String *S, String S1, String S2){S->length = S1.length + S2.length;StrInsert(S, 0, S1);StrInsert(S, S1.length, S2);}void SubString(String *Sub, String S, int pos, int len){int j = 0;for(int i = pos; i < pos+len; ++i){Sub->data[j++] = S.data[i];}Sub->length = len;}int Index(String S, String T, int pos){if(S.length == 0 || T.length == 0){return -1;}String Sub;InitString(&Sub);if(pos > 0){int s = S.length;int t = T.length;int i = pos;if(s < t)return -1;while ( i <= s - t + 1){SubString(&Sub, S, i, t);if(StrCompare(Sub, T) != 0)++i;elsereturn i+1;}}return 0;}int Index2(String S, String T, int pos){int s = S.length;int t = T.length;if(s < t || s < 0 || t < 0)return -1;int i = pos;int j = 0;while (i < s && j < t){if(S.data[i] == T.data[j]){++i;++j;}else{i = i - j + 1;j = 0;}}if(j >= t)return i - t + 1;elsereturn 0;}void StrDelete(String *S, int pos, int len){if(S->length < len){cout << "error" << endl;return ;}for(int i = pos - 1; i < S->length - len; ++i){S->data[i] = S->data[i + len];}S->length -= len;}


下面来看KMP算法:

   KMP算法是通过分析子串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后在上面的算法中使用。

他的时间复杂 度是O(m+n)  相比朴素比较算法O((n-m+1)*m)来说当然很快。

  本算法你需要知道如何构建next数组。  也就是你跟主串比较,子串中有相似项,其比较过后就不必再比较了。

        next是什么?

   next数组是你的串中各个位置   其当前字符之前的串的前后缀的相似度。(此时相似度我们看为j)

 如:abcabx;   x之前,前缀ab与后缀ab相同,此时他们的取值也就是3。 为何?  看图:



得出公式:



下面我们来看几个例子:





看到这里,我还想说的就是此时的next是有缺陷的,比如我们的主串是 S="aaaabcde"  子串是T="aaaaax“   那么他的next数组是 012345,   开始 i=5,j=5  我们发现b和a不等,  此时j=next【5】 = 4,  此时b和第四个位置的a也不想等

此时  j=next4 = 3.  直到j=next1 = 0为止,此时i++ j++得到i=6,j=1.


大家有木有发现此时2345步骤是多余的呢。  由于T的第二三四五位置的字符都与首位的a相等,那么可以用首位next1的值去取代与它相等的字符后续next的值,我们需要改进:


下面看几个例子:






下面看代码:

void get_nextval(String T, int *next){/*//待改进int t = T.length;int i = 1;int j = 0;next[1] = 0;while(i < t){if(j == 0 || T.data[i] == T.data[j]){++i;++j;next[i] = j;}elsej = next[j];}*///改进算法int t = T.length;int i = 1;int j = 0;next[1] = 0;while ( i < t){if(j == 0 || T.data[i] == T.data[j]){++i;++j;if(T.data[i] != T.data[j])next[i] = j;elsenext[i] = next[j];}elsej = next[j]; //若字符不同则回 朔}}int Index_KMP(String S, String T, int pos){int i = pos - 1;int s = S.length, t = T.length;int j = 1;int nexts[MAXSIZE];get_nextval(T, nexts);while ( i <= s && j <= t){if(j == 0 || S.data[i] == T.data[j-1]){++i;++j;}else{j = nexts[j];}}if( j > t )return i - t + 1;elsereturn 0;}


2013.8.2 

jofranks 于南昌