串
定义:即字符串,是由零个或多个字符组成的有限序列。
是一种特殊的线性表,数据元素之间呈现线性关系
串的数据对象限定为字符集(如中文字符、英文字符、数字字符、标点字符等)
串的基本操作:如增删改查通常以子串为操作对象
空串 VS 空格串 M='' :是空串 N=' ' :是由3个空格字符组成的空格串,每个空格字符占1B,即8bit
乱码问题???
原因: 编写和打开文件时使用的编码规则不一样
串的存储结构
- 顺序存储:
arduino
//---------串的顺序存储
#define MAXLEN 255 //预定义最大串长为255
//(静态数组实现)
typedef struct{
char ch[MAXLEN]; //每个分量存储一个字符
int length; //串的实际长度
}SString;
//求字串:用Sub返回串S的第pos个字符起长度为len的字串
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;
}
//比较两个串的大小:若S>T,返回值>0;若S=T,返回值=0;若S<T,返回值<0
int StrCompare(SString S, SString T){
for(int i = 0; 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 StrLength(SString S){
return S.length;
}
//定位操作。若主串S中存在与串T值相同的字串,则返回它在主串S中第一次
//出现的位置,否则函数值为0;
int Index(SString S, SString T){
int i = 1, n = StrLength(S), m = StrLength(T);
SString sub; //用于暂存子串
while(i <= n-m+1){
SubString(sub, S, i, m);
if(StrCompare(sub, T) != 0) ++i;
else return i; //返回子串在主串中的位置
}
return 0; //S中不存在与T相等的字串
}
//动态数组实现(堆分配存储)
typedef struct{
char *ch; //按串长分配存储区,ch指向串的基地址
int length; //串的长度
}HString;
//----------串的链式存储
typedef struct StringNode{
char ch[4]; //每个结点存多个字符
struct StringNode * next; //(指针占4b)
}StringNode, * String;
int main(int argc, char** argv) {
HString S;
S.ch = (char *)malloc(MAXLEN * sizeof(char));
S.length = 0;
return 0;
}
字符串模式匹配------------朴素模式匹配算法(暴力解决)
- 主串长度为n,模式串长度为m
- 解决:将主串中所有长度为m的子串 依次与模式串对比,(最多对比n-m+1个子串),直到找到一个完全匹配的字串,或所有的子串都不匹配为止。
- 上面的那个定位操作 就是实现了用字符串的基本操作来实现朴素模式匹配算法。
- 下面用数组下标来实现朴素模式匹配算法:
ini
// 数组下标实现模式匹配
int Index2(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 0;
}
- 设主串长度为n,模式串长度为m,则最坏时间复杂度 = O(nm)。最坏的情况,每个子串都要对比m个字符,共n-m+1个子串,复杂度 = O((n-m+1)m) = O(nm)
字符串模式匹配------------KMP算法(对朴素模式匹配算法的优化)
ini
//KMP算法
int Index_KMP(SString S, SString T, int next[]){
int i = 1, j = 1;
while(i <= S.length && j <= S.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;
}
//求模式串T的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;
//若pi=pj, 则next[j+1] = next[j] + 1
next[i] = j;
}
else
//否则令j = next[j],循环继续
j = next[j];
}
}
//求nextVal数组:先求next数组,再由next数组求nextVal数组
int[] get_nextVal(SString T, int next[]){
int nextval[T.length + 1];
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];
}
}
return nextval[];
}
//KMP算法(主串中的i指针不回溯,模板串中的j回溯)
int Index_KMP2(SString S, SString T){
int i = 1, j = 1;
int next[T.length + 1];
get_next(T, next); //求模式串的Next数组
while(i <= S.length && j <= T.length){
if(j == 0 || S.ch[i] == T.ch[j]){
++i;
++j;
}
else
j = next[j]; //j指针回溯
}
if(j > T.length)
return i-T.length; //匹配成功
else
return 0;
}