n=StrLength (s) ; /得到主串S的长度/
m = StrLength (T) ; /得到子串T的长度/
i = pos;
while (i <= n-m+1 )
{
SubString (sub,S,i,m) ;/取主串第i个位置/
/*长度与T相等子串给sub */
if (StrCompare (sub,T)!= 0) /★ 如果两串不相等*/
++i;
else /如果两串相等/
return i; /则返回i值/
}
}
return 0; /*若无子串与T相等,返回0 */
}
========================================================================
串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般是用定长数组来定义。
既然是定长数组,就存在一个预定义的最大串长度,一般可以将实际的串长度值保存在数组的0下标位置,有的书中也会定义存储在数组的最后一个下标位置。但也有些编程语言不想这么干,觉得存个数字占个空间麻烦。它规定在串值后面加一个不计入串长度的结束标记字符,比如“\0” 来表示串值的终结,这个时候,你要想知道此时的串长度,就需要遍历计算一下才 知道了,其实这还是需要占用一个空间,何必呢。
于是对于串的顺序存储,有一些变化, 串值的存储空间可在程序执行过程中动态分配而得。比如在计算机中存在-一个自由存储区,叫做“堆”。 这个堆可由C语言的动态分配函数malloc ()和free ()来管理。
对于串的链式存储结构,与线性表是相似的,但由于串结构的特殊性,结构中的每个元素数据是一个字符,如果也简单的应用链表存储串值,一个结点对应一个字符,就会存在很大的空间浪费。因此,一个结点可以存放一个字符, 也可以考虑存放多个字符,最后一个结点若是未被占满时,可以用“#”或其他非串值字符补全
当然,这里一个结点存多少个字符才合适就变得很重要,这会直接影响着串处理的效率,需要根据实际情况做出选择。串的链式存储结构除了在连接串与串操作时有一定方便之外,总的来说不如顺序存储灵活,性能也不如顺序存储结构好。
===========================================================================
在文章(相当于一个大串)中找到单词的定位,这种子串的定位操作通常称做串的模式匹配
这是串中很重要的操作之一
我们要找到主串S=“wyjbat”中,找到T = “bat”这个子串的位置。通常要进行下面的步骤。
1.主串S第一位开始,S与T字母进行匹配
2.多次比较从4位开始,S与T,3个字母全匹配,匹配成功
简单的说,就是对主串的每一个字符作为子串开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做T的长度的小循环,直到匹配成功或全部遍历完成为止。
这个算法也太低效了,不玩!!
============================================================================
三个科学家D.E.Knuth、 J.H.Morris 和V.R.Pratt,以他们的姓氏命名的
因为暴力匹配效率太低
比如我们要在主串中匹配子串ABCD,这很简单对吧,常规的思路就是一位一位的匹配(这个思路就是暴力匹配算法)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9kx80Ep-1637065551742)(C:/Users/Jack/AppData/Roaming/Typora/typora-user-images/image-20211116093132194.png)]
如果对不上了,我们让子串往后移动
上面这种思路可以用代码来实现
/**
-
暴力破解法
-
@param ts 主串
-
@param ps 模式串
-
@return 如果找到,返回在主串中第一个字符出现的下标,否则为-1
*/
public static int bf(String ts, String ps) {
char[] t = ts.toCharArray();
char[] p = ps.toCharArray();
int i = 0; // 主串的位置
int j = 0; // 模式串的位置
while (i < t.length && j < p.length) {
if (t[i] == p[j]) { // 当两个字符相同,就比较下一个
i++;
j++;
} else {
i = i - j + 1; // 一旦不匹配,i后退
j = 0; // j归0
}
}
if (j == p.length) {
return i - j;
} else {
return -1;
}
}
上面的程序没问题,只能说不够好!
主串匹配失败的位置除了第一个A之外再也没有A了,我们为什么知道主串前面只有一个A?因为前三个已经匹配过了啊!它们都是匹配的。
我们可以这样保存i不动,移动j
KMP算法的思想就是利用已经部分匹配的有效信息,保持i指针不回溯,通过修改j指针,让子串尽量的移动到有效的位置!
再详细的可以观看这篇文章,写的很好!
我就不更了,日后在更
(原创)详解KMP算法 - 孤~影 - 博客园 (cnblogs.com)
/通过计算返回子串T的next数组。/
void get_ next ( String T, int *next )
{
int i,j;
i=1;
j=0;
next[1]=0;
while ( i<T[0]) /此处T[0]表示串T的长度/
{
if (j0 11 T[i] T[j]) /* T[i]表示后缀的单个字符,*/
/* T[j]表示前缀的单个字符*/
{
++i;
++j;
next[i]=j;
}
else
j= next[j]; /若字符不相同,则j值回溯/
}
}
/返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。/
/* T非空,1SposSStrLength (s)。*/
int Index KMP (String s, String T, int pos )
{
int i= pos;/*i用于主串S当前位置下标值,若pos不为1, */
/则从pos位置开始匹配/
int j= 1; /j用于子串T中当前位置下标值/
int next[255] ; /定义一next数组/
get_ next(T, next); /对串工作分析,得到next数组/
while(i<= S[0] &j<= T[0]) /若i小于S的长度且j小于T的长度时,/
/循环继续/
{
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
/对串工作分析,得到next数组/
while(i<= S[0] &j<= T[0]) /若i小于S的长度且j小于T的长度时,/
/循环继续/
{
[外链图片转存中…(img-YFCZn7XN-1714322163869)]
[外链图片转存中…(img-JCZrO5YN-1714322163869)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!