当前位置:首页 > 编程笔记 > 正文
已解决

数据结构详细笔记——串

来自网友在路上 142842提问 提问时间:2023-10-19 14:54:39阅读次数: 42

最佳答案 问答题库428位专家为你答疑解惑

文章目录

  • 串的三要素
    • 逻辑结构(定义)
    • 数据的运算(基本操作)
    • 存储结构(物理结构)
      • 顺序串(顺序存储)
      • 链式串(链式存储)
  • 字符串模式匹配
    • 朴素模式匹配算法
      • 通过数组下标实现朴素模式匹配算法
    • KMP算法
      • 求模式串的next数组
      • KMP算法完整代码时间复杂度 O(n+m)
      • KMP算法的进一步优化


串的三要素

逻辑结构(定义)

串,即字符串(String)是由零个或多个字符组成的有限序列,串中字符的个数 n 称为串的长度。n=0 时的串称为空串。

串是一个特殊的线性表,数据元素之间呈线性关系

子串:串中任意个连续的字符组成的子序列
主串:包含子串的串
字符在主串中的位置:字符在串中的序号
子串在主串中的位置:子串的第一个字符在主串中的位置

数据的运算(基本操作)

StrAssign(&T,chars)
赋值操作:把串T赋值为charsStrCopy(&T,S)
复制操作:由串S复制得到串TStrEmpty(S)
判空操作:若S为空串,则返回true,否则返回falseStrLength(S)
求串长:返回串S的元素个数ClearString(&S)
清空操作:将S清为空串DestroyString(&S)
销毁串:将串S销毁(回收存储空间)Concat(&T,S1,S2)
串联接:用T返回由S1和S2联接而成的新串SubString(&Sub,pos,len)
求子串:用Sub返回串S的第pos个字符起长度了len的子串Index(S,T)
定位操作:若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置,否则函数值为0StrCompare(S,T)
比较操作:若S>T,返回值>0,若S=T,返回值=0,若S<T,返回值<0

存储结构(物理结构)

顺序串(顺序存储)

顺序串的定义
静态分配

#define MAXLEN 255    // 预定义最大串长为255
typedef struct{char ch[MAXLEN];int length;
}SString;

动态分配

typedef struct{char *ch;int length;
}HString;
HString S;
S.ch = (char *) malloc(MAXLEN*sizeof(char));
S.length = 0;

求子串

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 = 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相等的子串
}

链式串(链式存储)

存储密度低,每个字符1B,每个指针4B

typedef struct StringNode{char ch;  // 每一个结点存1个字符struct StringNode *next;  // 指针
}StringNode,*String;

提高存储密度

typedef struct StringNode{char ch[4];   // 每个结点存多个字符struct StringNode *next;
}StringNode,*String;

字符串模式匹配

字符串模式匹配:在主串中找到与模式串相同的子串,并返回其所在的位置

两种模式匹配的算法
1、朴素模式匹配算法
2、KMP算法

朴素模式匹配算法

主串长度为n,模式串长度为m
将主串中所有长度为m的子串依次与模式串对比,直到找到一个完全匹配的子串,或所有的子串都不匹配为止
最多对比 n-m+1个子串

Index(S,T) 定位操作就是利用了朴素模式匹配算法原理

通过数组下标实现朴素模式匹配算法

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;elsereturn 0;
}

设主串长度为n,模式串长度为m,则时间复杂度 O(nm)

朴素模式匹配算法的缺点:当某些子串与模式能部分匹配时,主串的扫描指针经常回溯,导致时间开销增加。

KMP算法

KMP算法:利用next数组进行匹配,减少回溯

int Index_KMP(SString S,SString T,int next[]){int i = 1, j = 1;whlie(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;  // 匹配成功elsereturn 0;
} 

代码中的next数组是:当模式串的第j个字符匹配失败时,令模式串跳到next【j】再继续匹配

求模式串的next数组

串的前缀:包含第一个字符,且不包含最后一个字符的子串
串的后缀:包含最后一个字符,且不包含第一个字符的子串

'abababcdef'
前缀:'abababcde'
后缀:'bababcdef'

当第j个字符匹配失败,由前 1~j-1个字符组成的串记为S,则next[j] = S的最长相等前后缀长度加1,
注意:next[1] = 0 , next[2] = 1

模式串:'ababaa'
当j=1时,next[1] = 0;
当j=2时,next[2] = 1;
当j=3时,S:ab, 前缀:a, 后缀:b, 前缀后缀相等长度为0 , next[3] = 0+1 = 1;
当j=4时,S:aba, 前缀:ab, 后缀:ba, 前缀后缀相等长度为0 , next[4] = 0+1 = 1;
当j=5时,S:abab, 前缀:aba, 后缀:bab, 前缀后缀相等最长串为ab,长度为2 , next[5] = 2+1 = 3;
当j=6时,S:ababa, 前缀:abab, 后缀:baba, 前缀后缀相等最长串为aba,长度为3 , next[6] = 3+1 = 4;所以得
序号j	1	2	3	4	5	6
模式串	a	b	a	b	a	a
next[j]	0	1	1	2	3	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++;// 若pi=pj,则next[j+1]=next[j]+1next[i] = j;} else {j = next[j];}}
}

KMP算法完整代码时间复杂度 O(n+m)

int Index_KMP(SString S,SString T){int i = 1, j = 1;int next[T.length+1];get_next(T,next);whlie(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;  // 匹配成功elsereturn 0;
} 

KMP算法的进一步优化

对于KMP算法色优化实际上是优化next数组,将next数组优化为nextval数组

例如上面的next数组
序号j		1	2	3	4	5	6
模式串		a	b	a	b	a	a
next[j]		0	1	1	2	3	4
nextval[j]	0	1	0	1	0	4//求nextval
netval[1] = 0;
for(int j=2; j<=T.length;mj++){if(T.ch[next[j]] == T.ch[j])nextval[j] = nextval[next[j]];elsenextval[j] = next[j];
}
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"数据结构详细笔记——串":http://eshow365.cn/6-19711-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!