赞
踩
串数据对象限定为字符集(中文字符、英文字符、数字字符、标点字符等等)
存储结构:
typedef struct {
char ch[MAXLEN];
int length;
}SString;
存储结构:
typedef struct {
char *ch;
int length;
}HString;
顺序串的实现细节:
方案一:使用int length的方法存储长度
特点:占用额外的空间,但是清楚明了,能够表示的串长范围大。
方案二:使用ch[0]存储length
特点:字符位序与数组下标相同,但是ch[0]只能存储1B数据,所以串长最多为256.
方案三:没有length变量,以 /0 表示结尾
特点:无法直接的表示串长。
方案四:不适用char[0],再使用length存储串长
特点:直观表示串长,并且数组下标与字符位序相同。
存储结构:
typedef struct StringNode{
char ch[4];
struct StringNode * next;
}StringNode,*String;
串的基本操作
bool SubString (SString &Sub,SString S,int pos,int len){
if (pos+len-1>S.length)
return false;
for (int i=pos;i<pos+len;i++){
Sub.ch[i-pos+1]=S.ch[i];
}
Sub.length=len;
return true;
}
int StrCompare(SString S,SString T){
for (int i=1;i<=S.length && i<=T.length;i++){
if (S.ch[i]!=T.ch[i])
return S.ch[i]-T.ch[i];
}
return S.length-T.length;
}
int Index(SString S,SString T){
int i=1,n=S.length,m=T.length;
SString sub;
while (i<=n-m+1){
SubString(sub,S,i,m);
if (StrCompare(sub,T)!=0)
i++;
else return i;
}
return 0;
}
算法思想与步骤:
int StringIndex(SString S,SString T){ int k=1; int i=k,j=1; while (i<=S.length&&j<=T.length){ if(S.ch[i]==T.ch[j]){ ++i; ++j; }else{ k++; i=k; j=1; } } if (j>T.length) return k; else return 0; }
性能分析
较好的情况:每个子串的第一个字符就与模式串不匹配。
若模式串的长度为m,主串长为n,则:
匹配成功的最好时间复杂度:O(m)
匹配失败的最好时间复杂度:O(n-m+1)=O(n-m)=O(n)
匹配成功的最坏时间复杂度:O[(n-m+1)*m]=O(mn)
匹配失败的最坏时间复杂度:O[(n-m+1)*m]=O(mn)
朴素算法缺点:匹配失败后模式串后移一位从头开始比较。某趟已匹配的相等的字符序列是模式的某个前缀,频繁的重复比较相当于模式串进行自我比较。
算法思想与步骤:
可知abcac的部分匹配值(PM)为00010,写为数组形式:
编号 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
S | a | b | c | a | c |
PM | 0 | 0 | 0 | 1 | 0 |
所以可知,当在第j位匹配失败时,子串的移动位数move:
move=已匹配字符数-对应部分的匹配值=j-1-PM[j-1]
利用数学推导从PM数组到next数组:
编号 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
S | a | b | c | a | c |
next | 0 | 1 | 1 | 1 | 2 |
next[j]的含义,在子串的第j个字符与主串发生失配时,则跳到子串的next[j]的位置重新与主串的当前位置进行比较
求法:当第j个字符匹配失败时,由1-j-1个字符组成的串记为S,则next[j]=S的最长相等前后缀长度+1。特别地next[1]=0。
函数表达式为:
n
e
x
t
[
j
]
=
{
0
j=1
M
a
x
k
∣
1
<
k
<
j
且
′
p
1
.
.
.
p
k
−
1
′
=
′
p
j
−
k
+
1
.
.
.
p
j
−
1
′
集合不为空时
1
其他情况
next[j]=
例:
模式串:‘ababaa’
编号 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
S | a | b | a | b | a | a |
next | 0 | 1 | 1 | 2 | 3 | 4 |
当j=1,next[1]=0
当j=2,‘a’->next[2]=0+1=1
当j=3,‘ab’->next[3]=0+1=1
当j=4,‘aba’->next[4]=1+1=2
当j=5,‘abab’->next[5]=2+1=3
当j=6,‘ababa’->next[6]=3+1=4
void get_next(SString T,int next[]){
int i=1,j=0;
next[1]=0;
while (i<T.length){
if (j==0 ||T.ch[i]==T.ch[j]){
++i;
++j;
next[i]=j;
}else {
j=next[j];
}
}
}
KMP算法的平均时间复杂度:O(n+m)
int Index_KMP(SString S,SString T){ int i=1,j=1; int next[MAXLEN]; get_next(T,next); while (i<=S.length && j<=T.length){ if (j==0 || S.ch[i]==T.ch[j]){ ++i; ++j; }else { j=next[j]; } if (j>T.length) return i-T.length; else return 0; } }
KMP缺陷:当不匹配字符前方有大量的相同字符时,会增加无意义匹配。
解决方法:优化next数组为nextval数组。
nextval数组求解方法:
例:
模式串:‘ababaa’
编号 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
S | a | b | a | b | a | a |
next | 0 | 1 | 1 | 2 | 3 | 4 |
编号 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
S | a | b | a | b | a | a |
nextval | 0 | 1 | 0 | 1 | 0 | 4 |
void get_nextval(SString T,int next[],int nextval[]){
nextval[1]=0;
for (int j=2;j<=T.length;j++){
if (T.ch[next[j]]==T.ch[j])
nextval[j]=nextval[next[j]];
else
nextval[j]=next[j];
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。