数据结构之串

来源:互联网 发布:access数据库编辑器 编辑:程序博客网 时间:2024/06/06 02:18

串:串是由零个货多个字符组成的有限序列,又名字符串。一般记为s="a1a2a3……an"(n>=0),其中,s是串的名称,用双引号括起来的字符序列是串的值。注意双引号不属于串的内容。串中的字符数目n称为串的长度。零个字符的串称为空串。

串中最重要的操作当属串的定位操作(子串的定位操纵通常称为串的模式匹配)

首先我们使用朴素的模式匹配算法:

算法描述:(这个很好理解,绘个图就很清楚了)

(1)有一个主串和一个子串,要在主串中查找子串。

(2)定义两个变量i,j,i指向主串,j指向子串。

(3)i指向主串第一个字母并于子串进行比较,如果不同,i就退到刚才位置的下一个。

(4)如果子串走到中间又不符合了,则主串的i退到刚才位置的下一个,子串j退到0重新开始。

代码示例如下:

int BF(const char *s,const char *sub,int pos){assert(s!=NULL && sub!=NULL);int lens = strlen(s);int lensub = strlen(sub);if(pos<0 || pos>=lens){return -1;}int i = pos;int j = 0;while(i<lens && j<lensub){if(s[i] == sub[j]){i++;j++;}else{i = i-j+1;j = 0;//j = k;?}}if(j>=lensub){return i-j;}else{return -1;}}

当然,这个算法的时间复杂度太大了O(m * n),我们可以对其进行优化。

KMP模式匹配算法:

该算法可以避免重复遍历的情况,提高算法的效率。可将算法的效率提高到O(m + n)。

相比于前面的朴素模式匹配算法,其主要的优化步骤是每次遍历,如果主串和子串发生“失配”,则主串不后退,子串后退,关键就在子串后退位置的选择上。

我们对于子串退的位置算法总结如下:

在匹配相等的子串中,查找两个相等的真子串,这两个相等的真子串需要符合以下几点:

(1)一个子串以子串首字母开头;

(2)另一个以匹配相等的子串的最后一个字符结尾

在设计上,我们可以采用一个数组存储子串后退的位置,按照上面的规则,我们做一个示范:

如:“ababcabcdabce”

则next[]数组为:x0012012001200(根据串的存储理解,有时需要加1)

代码为:

void GetNext(const char *sub,int *next){int len = strlen(sub);next[0] = -1;next[1] = 0;int j =1;int k = 0;while(j+1<len){if((k==-1) || sub[k] == sub[j]){/*next[j+1] = k+1;j++;k++;*/next[++j] = ++k;}else{k = next[k];}}}int KMP(const char *s,const char *sub,int pos){assert(s!=NULL && sub!=NULL);int lens = strlen(s);int lensub = strlen(sub);if(pos<0 || pos>=lens){return -1;}int i = pos;int j = 0;int *next = (int *)malloc(lensub*sizeof(int));GetNext(sub,next);while(i<lens && j<lensub){if((j==-1) || (s[i]==sub[j])){i++;j++;}else{j = next[j];}}if(j>=lensub){return i-j;}else{return -1;}}
这里有个问题:如果我这个子串很长,那么我还是申请数组存储吗?容我想想……

我们再对上述KMP算法再进行优化:

然而这次要借助next[]数组的值,不过最终后退位置是由nextval[]数组来保存的。

方法是:

(1)nextval[0] = -1,nextval[1]=0

(2)当n>=2时,比较当前字符和next[]数组中存储位置的值是否相同,如果相同,就后退到next[]数组对应的前一个,如果不同,就还是当前next[]数组中的值。

示例:

s:"ababaaaba"

next{}:x00123112

nextval[]:x0x0x310x(x:-1)

参考代码:

void GetNext(const char *sub,int *next){int len = strlen(sub);next[0] = -1;next[1] = 0;int j =1;int k = 0;while(j+1<len){if((k==-1) || sub[k] == sub[j]){next[++j] = ++k;}else{k = next[k];}}}//KMP改进算法void Reverse_GetNext(const char *sub,int *nextval){int lensub=strlen(sub);int k=-1;int j=2;nextval[0]=-1;nextval[1]=0;int *next = (int *)malloc(lensub*sizeof(int));GetNext(sub,next);while(j<lensub){<span style="color:#ff0000;">if(sub[j] == sub[(next[j])]){nextval[j] =nextval[(next[j])];}else{nextval[j] = next[j];}</span>}}//KMP基本算法int KMP(const char *s,const char *sub,int pos){assert(s!=NULL && sub!=NULL);int lens = strlen(s);int lensub = strlen(sub);if(pos<0 || pos>=lens){return -1;}int i = pos;int j = 0;int *nextval = (int *)malloc(lensub*sizeof(int));GetNext(sub,nextval);while(i<lens && j<lensub){if((j==-1) || (s[i]==sub[j])){i++;j++;}else{//j = next[j];j = nextval[j];}}if(j>=lensub){return i-j;}else{return -1;}}

欢迎指导


0 0
原创粉丝点击