字符串
定义和基本操作
定义
- 由零个或多个字符组成的优先序列
基本操作
StrAssign(&T, chars)赋值。把字符串T赋值为charsStrCopy(&T, S)复制。由S复制到TStrEmpty(S)判空StrLength(S)求长度ClearString(&S)清空DestroyString(&S)销毁。回收存储空间Contact(&T,&T1,&T2)联接,返回S1和S2联接的新串SubString(&sub, S, pos, len)求子串,第pos字符开始长度为len的子串Index(S,T)定位操作,返回S中存在T相同的子串的位置,否则返回-1StrCompare(S,T)比较操作
字符集编码
- 任何数据在计算机中一定是二进制
- 字符集:英文字符,ASCII字符,中英文,Unicode字符集
- 基于同一个字符集可以有不同编码方式:UTF-8,GBK
- 不同的编码方式,字符占用的空间不同
存储结构
顺序存储
- 方案1: 一个数组存储字符,一个int变量存储实际长度
- 方案2: 数组的ch[0]充当长度,优点:字符的位序和数组下标相同
- 方案3: 没有长度变量,已字符’\0’表示结尾,缺点:获取长度需要遍历
- 方案4: ch[0]废弃不用,外加一个长度变量

链式存储

基本操作实现-第四种方案



匹配问题-朴素算法
方法1
- 将主串中所有长度为m的子串依次与模式串对比,直到找到一个完全匹配的子串,或所有子串都不匹配为止
- 主串长度为n,模式串长度为m, 最多对比 n - m + 1个子串
方法2
- 使用两个指针i和j进行匹配,如果当前子串匹配失败,则主串指针i指向下一个子串的第一个位置,模式串指针j回到模式串的第一个位置,即 i = i - j + 2; j = 1;
如果 j > T.length, 则当前串匹配成功,返回第一个字符的位置即 i - T.length
int Index(SString S, SString T) { int i = 1, j = 1; while(i <= S.length && j <= T.length) { if (S.ch[i] == T.ch[j]) { i++; j++; } else { i = i - j + 2; j = 1; } } if (j > T.length) { return i - T.length; } else { return -1; } }
匹配问题-KMP算法
- 原理:减少i指针的回溯,通过已经计算好的next指针,提高算法效率
- 精髓:利用好已经匹配过的模式串信息
- next数组记录了当第几个元素匹配失败的时候,j的取值
步骤
- 根据模式串T,求出next数组
- 利用next数组进行匹配(主串指针不回溯)

求next数组
- 当模式串的第j个字符匹配失败时,从模式串的第next[j]的继续往后匹配
步骤
- 第一个字符不匹配时,只能匹配下一个子串,因此next[1]都无脑写0
if(j==0){i++;j++} - 第二个字符不匹配时,应尝试匹配模式串的第一个字符,因此next[2]都无脑写1
第三个字符及之后的,在不匹配的位置前边,划一根美丽的分界线模式串一步步往后退,直到分界线之前能对上,此时j指向哪儿,next数组值就是多少
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]; } } }