字符串
串:字符串,有零个或者多个字符组成的有限序列
串长:串中字符的个数
空串:零个字符的串
子串:串中任意个连续字符组成的子序列。原串称为主串
字符串的存储可以使用顺序存储和链式存储两种方式。
顺序存储 用一段连续的空间存储字符串。可以预先分配一个固定长度Maxsize的空间在这个空间中存储字符串。
以**’\0’**表示字符串的结束(C/C++、Java)。
在0空间存储字符串的长度。下标0的空间不使用,因此可以预先分配Maxsize+1的空间,在下标为0的空间存储字符串长度。
结构体变量存储字符串长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef struct Str { char ch[Maxsize]; int length; } typedef struct Str { char *ch; int length; }
链式存储 顺序存储的串在插入和删除操作时,需要移动大量元素,因此也可以采用链表的形式存储。
模式匹配 子串的定位运算称为串的模式匹配或串匹配。
BF算法 暴力匹配
最好情况:每一次都在第一次比较时发现不等,最好情况下的平均时间复杂度为$O(n+m)$
最坏情况:每一次都匹配到T的最后一个字符发现不等。回退重新开始。最坏情况下的平均时间复杂度为$O(m*n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <stdio.h> int bf (char *s, char *t) { int index = 0 , i = 0 , j = 0 ; while (s[i] != '\0' && t[j] != '\0' ) { if (s[i] == t[j]) { i ++; j ++; } else { index ++; i = index; j = 0 ; } } if (t[j] == '\0' ) { return index; } return -1 ; } int main (int argc, char *argv[]) { char *s = "asssasdfasdf" ; char *t = "sdf" ; printf ("index = %d\n" , bf(s, t)); return 0 ; }
KMP算法 KMP的核心在于回退的位置,回退时保证前面的字符相等,也就是求最大相同的前缀和后缀。
部分匹配表(PMT, Partial Match Table),如匹配的字符如下:
char
index
pmt
next
a
0
0
-1
b
1
0
0
a
2
1
0
b
3
2
1
a
4
3
2
b
5
4
3
c
6
0
4
a
7
1
0
index为1时,a!=b,则pmt=0,next也回溯到下标0
index为2时,存在a=a,而ab!=ba,所以pmt=1,next也回溯到a的下标0的位置
index为3时,存在ab=ab,所以pmt为2,当匹配到ababa,时最后一个a不相等时即可回溯到下标为1的位置,因为前面的ab都相等。
…
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <stdio.h> #include <string.h> #include <stdlib.h> int * getNext (char *t) { int len = strlen (t); int *next = (int *) malloc (sizeof (int ) * len); int i = 0 , j = -1 ; next[0 ] = -1 ; while (i < len) { if (j == -1 || t[i] == t[j]) { i ++; j ++; next[i] = j; } else { j = next[j]; } } return next; } int kmp (char *s, char *t) { int *next = getNext(t); printf ("the next array is : [" ); for (int i = 0 ; i < strlen (t); ++i) { printf ("%d " , next[i]); } printf ("]\n" ); int i = 0 , j = 0 ; int slen = strlen (s); int tlen = strlen (t); while (i < slen && j < tlen) { if (j == -1 || s[i] == t[j]) { i ++; j ++; } else { j = next[j]; } } free (next); if (j == tlen) { return i-j; } return -1 ; } int main (int argc, char *argv[]) { char *t = "abababca" ; char *s = "1231saabababca1asdf" ; int r = kmp(s, t); printf ("result is : %d\n" , r); return 0 ; }