串采用定长顺序存储结构的基本操作改进KMP算法
串的定义及其基本运算
4.2串的定长顺序存储及基本运算
4.2.1存储结构的实现
#define MAXSIZE 256 第一种: typedef struct {char data[MAXSIZE]; int curlen; }SeqString;
0 s.data a 第二种: b c d e f g h i 1 2 3 4 5 6 7 8
j=1 j=3 j=2 j=4
i=2 i=4 i=3 i=5
j 模式串 next[j]
i=5
1 2
0 1
3
1
4
1
5
2
6
2
7
3
8
2
9
3
a b c a a b a b c
s: a a b c b a b c a a b c a a b a b c t: abcaababc
j=1 i=6 i=7i=8 i=10 i=12 i=9 i=11 i=10 i=12
MAXSIZE
4.2.2运算实现(采用第二种表示串长的方式) int StrLength(char s[]) 1. 求串的长度 StrLength(s); {int len=0;
while(s[len]!=‘\0’)len++; return len; }
2.串赋值 void StrAssign(s1,s2) StrAssign(s1,s2); char s1[ ], s2[ ] ;
j=3 j=5 j=7 j=9 j=4 j=6 j=8 j=10
(3)KMP算法实现 循环条件? 什么时候回溯? 回溯时i、j如何计算? 如何判断匹配是否成功? 匹配成功时,返回的起始位置如何计算?
见P61的算法4-5
2022年西安交通大学计算机科学与技术专业《数据结构与算法》科目期末试卷A(有答案)
2022年西安交通大学计算机科学与技术专业《数据结构与算法》科目期末试卷A(有答案)一、选择题1、有一个100*90的稀疏矩阵,非0元素有10个,设每个整型数占2字节,则用三元组表示该矩阵时,所需的字节数是()。
A.60B.66C.18000D.332、将两个各有N个元素的有序表归并成一个有序表,其最少的比较次数是()。
A.NB.2N-1C.2ND.N-13、某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用()存储方式最节省运算时间。
A.单链表B.仅有头指针的单循环链表C.双链表D.仅有尾指针的单循环链表4、已知有向图G=(V,E),其中V={V1,V2,V3,V4,V5,V6,V7}, E={<V1,V2>,<V1,V3>,<V1,V4>,<V2,V5>,<V3,V5>, <V3,V6>,<V4,V6>,<V5,V7>,<V6,V7>},G的拓扑序列是()。
A.V1,V3,V4,V6,V2,V5,V7B.V1,V3,V2,V6,V4,V5,V7C.V1,V3,V5,V2,V6,V7D.V1,V2,V5,V3,V4,V6,V75、用不带头结点的单链表存储队列,其队头指针指向队头结点,队尾指针指向队尾结点,则在进行出队操作时()。
A.仅修改队头指针B.仅修改队尾指针C.队头、队尾指针都可能要修改D.队头、队尾指针都要修改6、已知字符串S为“abaabaabacacaabaabcc”,模式串t为“abaabc”,采用KMP算法进行匹配,第一次出现“失配”(s!=t)时,i=j=5,则下次开始匹配时,i和j的值分别()。
A.i=1,j=0 B.i=5,j=0 C.i=5,j=2 D.i=6,j=27、循环队列放在一维数组A中,end1指向队头元素,end2指向队尾元素的后一个位置。
2022年中国农业大学计算机科学与技术专业《数据结构与算法》科目期末试卷A(有答案)
2022年中国农业大学计算机科学与技术专业《数据结构与算法》科目期末试卷A(有答案)一、选择题1、n个结点的完全有向图含有边的数目()。
A.n*nB.n(n+1)C.n/2D.n*(n-1)2、哈希文件使用哈希函数将记录的关键字值计算转化为记录的存放地址,因为哈希函数是一对一的关系,则选择好的()方法是哈希文件的关键。
A.哈希函数B.除余法中的质数C.冲突处理D.哈希函数和冲突处理3、静态链表中指针表示的是()。
A.下一元素的地址B.内存储器的地址C.下一元素在数组中的位置D.左链或右链指向的元素的地址4、已知串S='aaab',其next数组值为()。
A.0123B.1123C.1231D.12115、在下列表述中,正确的是()A.含有一个或多个空格字符的串称为空格串B.对n(n>0)个顶点的网,求出权最小的n-1条边便可构成其最小生成树C.选择排序算法是不稳定的D.平衡二叉树的左右子树的结点数之差的绝对值不超过l6、下列选项中,不能构成折半查找中关键字比较序列的是()。
A.500,200,450,180 B.500,450,200,180C.180,500,200,450 D.180,200,500,4507、若一棵二叉树的前序遍历序列为a,e,b,d,c,后序遍历序列为b, c,d,e,a,则根结点的孩子结点()。
A.只有e B.有e、b C.有e、c D.无法确定8、有n(n>0)个分支结点的满二叉树的深度是()。
A.n2-1B.log2(n+1)+1C.log2(n+1)D.log2(n-l)9、在下述结论中,正确的有()。
①只有一个结点的二叉树的度为0。
②二叉树的度为2。
③二叉树的左右子树可任意交换。
④深度为K的完全二叉树的结点个数小于或等于深度相同的满二叉树。
A.①②③B.⑦③④C.②④D.①④10、一组记录的关键码为(46,79,56,38,40,84),则利用快速排序的方法,以第一个记录为基准得到的一次划分结果为()。
1下面关于串叙述中
第四章串一、选择题1.下面关于串的的叙述中,哪一个是不正确的?()【北方交通大学 2001 一、5(2分)】A.串是字符的有限序列 B.空串是由空格构成的串C.模式匹配是串的一种重要运算 D.串既可以采用顺序存储,也可以采用链式存储2 若串S1=‘ABCDEFG’, S2=‘9898’ ,S3=‘###’,S4=‘012345’,执行concat(replace(S1,substr(S1,length(S2),length(S3)),S3),substr(S4,index(S2,‘8’),length(S2)))其结果为()【北方交通大学 1999 一、5 (25/7分)】A.ABC###G0123 B.ABCD###2345 C.ABC###G2345 D.ABC###2345E.ABC###G1234 F.ABCD###1234 G.ABC###012343.设有两个串p和q,其中q是p的子串,求q在p中首次出现的位置的算法称为()A.求子串 B.联接 C.匹配 D.求串长【北京邮电大学 2000 二、4(20/8分)】【西安电子科技大学 1996 一、1 (2分)】4.已知串S=‘aaab’,其Next数组值为()。
【西安电子科技大学 1996 一、7 (2分)】A.0123 B.1123 C.1231 D.12115.串‘ababaaababaa’的next数组为()。
【中山大学 1999 一、7】A.0 B.0 C.0 D.06.字符串‘ababaabab’的nextval 为()A.(0,1,0,1,04,1,0,1) B.(0,1,0,1,0,2,1,0,1)C.(0,1,0,1,0,0,0,1,1) D.(0,1,0,1,0,1,0,1,1 )【北京邮电大学 1999 一、1(2分)】7.模式串t=‘abcaabbcabcaabdab’,该模式串的next数组的值为(),nextval数组的值为()。
数据结构教程李春葆课后答案第4章串
8. 采用顺序结构存储串,设计一个实现串通配符匹配的算法 pattern_index(),其中的 通配符只有‘?’ ,它可以和任一个字符匹配成功。例如,pattern_index("?re","there are") 返回的结果是 2。 解:采用 BF 算法的穷举法的思路,只需要增加对‘?’字符的处理功能。对应的算法 如下:
void maxsubstr(SqString s,SqString &t) { int maxi=0,maxlen=0,len,i,j,k; i=0; while (i<s.length) //从下标为 i 的字符开始 { j=i+1; //从 i 的下一个位置开始找重复子串 while (j<s.length) { if (s.data[i]==s.data[j]) //找一个子串,其起始下标为 i,长度为 len { len=1; for(k=1;s.data[i+k]==s.data[j+k];k++) len++; if (len>maxlen) //将较大长度者赋给 maxi 与 maxlen { maxi=i; maxlen=len; } j+=len; } else j++; } i++; //继续扫描第 i 字符之后的字符 } t.length=maxlen; //将最长重复子串赋给 t for (i=0;i<maxlen;i++) t.data[i]=s.data[maxi+i]; }
SqString CommChar(SqString s1,SqString s2) { SqString s3; int i,j,k=0; for (i=0;i<s1.length;i++) { for (j=0;j<s2.length;j++) if (s2.data[j]==s1.data[i]) break; if (j<s2.length) //s1.data[i]是公共字符 { s3.data[k]=s1.data[i]; k++; } } s3.length=k; return s3; }
中科院864程序设计考研大纲
中国科学院大学硕士研究生入学考试《程序设计》考试大纲本《程序设计》考试大纲适用于中国科学院大学计算机科学与技术类的硕士研究生入学考试。
程序设计是计算机科学与技术及相关学科的重要基础,主要内容包括数据结构和C 程序设计两大部分。
要求考生对计算机科学与技术及相关学科的基本概念有较深入、系统的理解,掌握各种数据结构的定义和实现算法,对C语言的基本知识有较深入的了解,掌握程序设计的基本方法,并具有综合运用所学知识分析问题和解决问题的能力。
一、考试内容数据结构1、绪论(1)数据结构的基本概念,数据的逻辑结构、存储结构。
(2)算法的定义、算法的基本特性以及算法分析的基本概念。
2、线性表(1)线性关系、线性表的定义,线性表的基本操作。
(2)线性表的顺序存储结构与链式存储结构(包括单链表、循环链表和双向链表)的构造原理。
在以上两种存储结构上对线性表实施的最主要的操作(包括三种链表的建立、插入和删除、检索等)的算法设计。
3、堆栈与队列(1)堆栈与队列的基本概念、基本操作。
(2)堆栈与队列的顺序存储结构与链式存储结构的构造原理。
(3)在不同存储结构的基础上对堆栈与队列实施插入与删除等基本操作对应的算法设计。
4、串(1)串的基本概念、串的基本操作和存储结构。
(2)串的模式匹配算法和改进的KMP算法5、数组和广义表(1)数组的概念、多维数组的实现(2)对称矩阵和稀疏矩阵的压缩存储(3)广义表的基本概念6、树与二叉树(1)树的定义和性质(2)二叉树的概念、性质和实现(3)遍历二叉树和线索二叉树(4)树和森林(5)赫夫曼树及其应用(6)树的计数7、图(1)图的定义,基本概念,图的分类,常用名词术语。
(2)图的邻接矩阵存储方法、邻接表存储方法的构造原理。
(3)图的遍历操作。
(4)最小生成树,最短路径,AOV网与拓扑排序。
8、文件及查找(1)数据文件的基本概念和基本术语,数据文件的基本操作。
(2)顺序文件、索引文件、散列(Hash)文件。
KMP算法(改进的模式匹配算法)——next函数
KMP算法(改进的模式匹配算法)——next函数KMP算法简介KMP算法是在基础的模式匹配算法的基础上进⾏改进得到的算法,改进之处在于:每当匹配过程中出现相⽐较的字符不相等时,不需要回退主串的字符位置指针,⽽是利⽤已经得到的部分匹配结果将模式串向右“滑动”尽可能远的距离,再继续进⾏⽐较。
在KMP算法中,依据模式串的next函数值实现字串的滑动,本随笔介绍next函数值如何求解。
next[ j ]求解将 j-1 对应的串与next[ j-1 ]对应的串进⾏⽐较,若相等,则next[ j ]=next[ j-1 ]+1;若不相等,则将 j-1 对应的串与next[ next[ j-1 ]]对应的串进⾏⽐较,⼀直重复直到相等,若都不相等则为其他情况题1在字符串的KMP模式匹配算法中,需先求解模式串的函数值,期定义如下式所⽰,j表⽰模式串中字符的序号(从1开始)。
若模式串p 为“abaac”,则其next函数值为()。
解:j=1,由式⼦得出next[1]=0;j=2,由式⼦可知1<k<2,不存在k,所以为其他情况即next[2]=1;j=3,j-1=2 对应的串为b,next[2]=1,对应的串为a,b≠a,那么将与next[next[2]]=0对应的串进⾏⽐较,0没有对应的串,所以为其他情况,也即next[3]=1;j=4,j-1=3 对应的串为a,next[3]=1,对应的串为a,a=a,所以next[4]=next[3]+1=2;j=5,j-1=4 对应的串为a,next[4]=2,对应的串为b,a≠b,那么将与next[next[4]]=1对应的串进⾏⽐较,1对应的串为a,a=a,所以next[5]=next[2]+1=2;综上,next函数值为 01122。
题2在字符串的KMP模式匹配算法中,需先求解模式串的函数值,期定义如下式所⽰,j表⽰模式串中字符的序号(从1开始)。
若模式串p为“tttfttt”,则其next函数值为()。
串-第4章-《数据结构题集》答案解析-严蔚敏吴伟民版
串-第4章-《数据结构题集》答案解析-严蔚敏吴伟民版习题集解析部分第4章串——《数据结构题集》-严蔚敏.吴伟民版源码使⽤说明链接☛☛☛课本源码合辑链接☛☛☛习题集全解析链接☛☛☛相关测试数据下载链接☛本习题⽂档的存放⽬录:数据结构\▼配套习题解析\▼04 串⽂档中源码的存放⽬录:数据结构\▼配套习题解析\▼04 串\▼习题测试⽂档-04源码测试数据存放⽬录:数据结构\▼配套习题解析\▼04 串\▼习题测试⽂档-04\Data⼀、基础知识题4.1❶简述空串和空格串(或称空格符串)的区别。
4.2❷对于教科书4.1节中所述串的各个基本操作,讨论是否可由其他基本操作构造⽽得,如何构造?4.3❶设s = ‘I AM A STUDENT’,t = ‘GOOD’,q = ‘WORKER’。
求:StrLength(s),StrLength(t),SubString(s, 8, 7),SubString(t, 2, 1),Index(s, ‘A’),Index(s, t),Replace(s, ‘STUDENT’, q),Concat(SubString(s, 6, 2), Concat(t, SubString(s, 7, 8)))。
4.4❶已知下列字符串a = ‘THIS’, f = ‘A SAMPLE’, c = ‘GOOD’, d = ‘NE’,b = ‘ ’.s = Concat(a, Concat(SubString(f, 2, 7), Concat(b, SubString(a, 3, 2)))),t = Replace(f, SubString(f, 3, 6), c),u = Concat(SubString(c, 3, 1), d),g = ‘IS’,v = Concat(s, Concat(b, Concat(t, Concat(b, u)))),试问:s,t,v,StrLength(s),Index(v, g),Index(u, g)各是什么?4.5❶试问执⾏以下函数会产⽣怎样的输出结果?void demonstrate(){StrAssign(s, ‘THIS IS A BOOK’);Replace(s, SubString(s, 3, 7), ‘ESE ARE’);StrAssign(t, Concat(s, ‘S’));StrAssign(u, ‘XYXYXYXYXYXY’);StrAssign(v, SubString(u, 6, 3));StrAssign(w, ‘W’);printf(‘t=’, t, ‘v=’, v, ‘u=’, Replace(u, v, w));}//demonstrate4.6❷已知:s = ‘(XYZ)+*’,t = ‘(X+Z)*Y’。
2019年中国科学院大学862计算机学科综合考研大纲与参考书目
2019年中国科学院大学862计算机学科综合(非专业)考研初试大纲《计算机学科综合(非专业)》考试大纲本《计算机学科综合(非专业)》考试大纲适用于中国科学院大学非计算机科学与技术一级学科下各专业的硕士研究生入学考试。
《计算机学科综合(非专业)》主要内容包括数据结构、操作系统和计算机网络三大部分。
要求考生对计算机科学与技术及相关学科的基本概念有较深入、系统的理解;掌握各种数据结构的定义和实现算法;掌握操作系统和计算机网络所涉及的关键内容,并具有综合运用所学知识分析问题和解决问题的能力。
一、考试内容数据结构1、绪论(1)数据结构的基本概念,数据的逻辑结构、存储结构。
(2)算法的定义、算法的基本特性以及算法分析的基本概念。
2、线性表(1)线性关系、线性表的定义,线性表的基本操作。
(2)线性表的顺序存储结构与链式存储结构(包括单链表、循环链表和双向链表)的构造原理。
在以上两种存储结构上对线性表实施的最主要的操作(包括三种链表的建立、插入和删除、检索等)的算法设计。
3、堆栈与队列(1)堆栈与队列的基本概念、基本操作。
(2)堆栈与队列的顺序存储结构与链式存储结构的构造原理。
(3)在不同存储结构的基础上对堆栈与队列实施插入与删除等基本操作对应的算法设计。
4、串(1)串的基本概念、串的基本操作和存储结构。
(2)串的模式匹配算法和改进的KMP算法5、数组和广义表(1)数组的概念,以及表示和实现(2)矩阵(对称矩阵和稀疏矩阵)的压缩存储(3)广义表的基本概念6、树与二叉树(1)树的定义和性质(2)二叉树的概念、性质和实现(3)遍历二叉树和线索二叉树(4)树和森林(5)赫夫曼树及其应用(6)回溯法与树的遍历(7)树的计数7、图(1)图的定义,基本概念,图的分类,常用名词术语。
(2)图的邻接矩阵存储方法、邻接表存储方法的构造原理。
(3)图的遍历操作。
(4)图的连通性、最小生成树(5)最短路径的计算(6)AOV网与拓扑排序。
KMP算法详解
KMP算法详解KMP 算法详解KMP 算法是⼀个⼗分⾼效的字符串查找算法,⽬的是在⼀个字符串 s 中,查询 s 是否包含⼦字符串 p,若包含,则返回 p 在 s 中起点的下标。
KMP 算法全称为 Knuth-Morris-Pratt 算法,由 Knuth 和 Pratt 在1974年构思,同年 Morris 也独⽴地设计出该算法,最终由三⼈于1977年联合发表。
举⼀个简单的例⼦,在字符串 s = ababcabababca 中查找⼦字符串 p = abababca,如果暴⼒查找,我们会遍历 s 中的每⼀个字符,若 s[i] = p[0],则向后查询p.length() 位是否都相等。
这种朴素的暴⼒的算法复杂度为O(m×n),其中m和n分别是 p 和 s 的长度。
KMP 算法可以⽅便地简化这⼀查询的时间复杂度,达到O(m+n)。
1. PMT 序列PMT 序列是 KMP 算法的核⼼,即 Partial Match Table(部分匹配表)。
举个例⼦:char a b a b a b c aindex01234567PMT00123401PMT 的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。
PMT[0] = 0: 字符串 a 既没有前缀,也没有后缀;PMT[1] = 0: 字符串 ab 前缀集合为 {a},后缀集合为 {b},没有交集;PMT[2] = 1: 字符串 aba 前缀集合为 {a, ab},后缀集合为 {ba, a},交集为 {a},交集元素的最长长度为1;PMT[3] = 2: 字符串 abab 前缀集合为 {a, ab, aba},后缀集合为 {bab, ab, b},交集为 {ab},交集元素的最长长度为2;…… 以此类推。
2. 算法主体现在我们已经知道了 PMT 序列的含义,那么假设在 PMT 序列已经给定的情况下,如何加速字符串匹配算法?tar 存储 s 的下标,从 0 开始,若 tar > s.length() - 1,代表匹配失败;pos 存储 p 的下标,从 0 开始,若 s[tar] != p[pos],则 pos ⾛到下⼀个可能匹配的位置。
数据结构习题
第一章知识点:1.基本概念: 数据结构分类、特点等:如线性结构,是数据元素之间存在一种( 一对一关系)数据元素的概念(数据项)2.时空复杂度1、设有数据结构(D ,R ),其中D={d1,d2,d3,d4,d5,d6},R=r ,r={(d1,d2),(d2,d3),(d3,d4),(d2,d5),(d3,d5)}试按照图论中的画法画出其逻辑结构图。
2、称算法的时间复杂度为O(f(n)),其含义是指算法的执行时间和_【1】_的数量级相同。
3. 计算下面程序段的时间复杂度。
x=0;for(i=1; i<n; i++)for (j=1; j<=n-i; j++)x++;解:因为x++共执行了n-1+n-2+……+1= n(n-1)/2,所以执行时间为O (n 2).4. 计算下面程序段的时间复杂度。
x=n;y=0; 解:设@执行了t(n)次,则(t(n)+1)2<=n ,推出t(n)<=n 1/2-1。
所以时间复杂度为O (n 1/2).5. 分析下面各程序段的时间复杂度 (1) O(n*m) (2) O(log 3n)1)for (i=0; i<n; i++)for (j=0; j<m; j++)A[i][j]=0;2) i=1;while(i<=n) i=i*3;6. 在n 个结点的顺序表中,算法的时间复杂度是O (1)的操作是:A(A )访问第i 个结点(1≤i ≤n )和求第i 个结点的直接前驱(2≤i ≤n ) (B )在第i 个结点后插入一个新结点(1≤i ≤n ) (C )删除第i 个结点(1≤i ≤n ) (D ) 将n 个结点从小到大排序第二章 线性表知识点:顺序表、单链表、双向链表(插入、查找、删除运算)循环链表(单双向)特点, 考点:基本操作、复杂度、特点、算法应用1.在一个单链表中,若p所指结点是q所指结点的前驱结点,则删除结点q的正确操作是( B )A. p->next=qB. p->next=q->nextC. p=q->nextD. p->next=q->next->next2、在一个头指针为head的带头结点单链表中,要向表头插入一个由指针p指向的结点,则应执行【4】p->next=head->next;、【5】head->next=p。
串的模式匹配算法
/* 在目标串s中找模式串t首次出现的位置,若不存在返回0。采用定长顺序
存储结构第二种方式存放串S和串T */
{
int i,j;
for(i=1,j=1;i<=s.length&&j<=t.length;)
{if(s.ch[i-1]==t.ch[j-1])
{i++;j++;}
/*字符比较成功,继续比较后续字符*/
设有两个串S和T,其中: S="s1s2s3…sn" T="t1t2t3…tm"(1≤m≤n,通常有m<n)
模式匹配算法的基本思想是:用T中字符依次与S中 字符比较:从S中的第一个字符(i=1)和T中第一个字 符( j=1)开始比较,如果s1=t1,则i和j各加1,继续 比较后续字符,若s1=t1,s2=t2,…,sm=tm, 返回1;否则,一定存在某个整数j(1≤j≤m)使得si≠tj ,即第一趟匹配失败,一旦出现这种情况,立即中断 后面比较,将模式串T向右移动一个字符执行第二趟 匹配步骤,即用T中第一个字符( j=1)与S中的第2个字 符(i=2)开始依次比较;
数据结构
串的模式匹配算法
基本的模式匹配算法
子串定位操作又称为串的模式匹配(Pattern Matching)或串匹配,该操作是各种串处理系统中的 重要操作之一 。
子串定位操作是要在主串中找出一个与子串相同的 子串。一般将主串称为目标串,子串称之为模式串。 设S为目标串,T为模式串,把从目标串S中查找模式串 T的过程成为“模式匹配”。匹配的结果有两种:如果 S中有模式为T的子串,则返回该子串在S中的位置,若 S中有多个模式为T的子串时,则返回的是模式串T在S 中第一次出现的位置,这种情况称匹配成功;否则,称 为匹配失败。
第4章 串
数
据
结
构
与
算
法
(4)串比较(compare) int strcmp(char *s1,char *s2); 该函数比较串s1和串s2的大小,当返回值小于0,等于0 或大于0时分别表示s1<s2、s1=s2或s1>s2 例如:result=strcmp(“baker”,”Baker”) result>0 result=strcmp(“12”,”12”); result=0 result=strcmp(“Joe”,”Joseph”); result<0 (5)字符定位(index) char strchr(char *s,char c); 该函数是找字符c在字符串中第一次出现的位置,若找到 则返回该位置,否则返回NULL。 例如:p=strchr(s2,’.’); p 指向“file”之后的位置 s2=“file.cpp”
}
沈阳工业大学
数
据
结
构
与
算
法
2堆分配存储表示
这种存储表示的特点是,仍以一组地址连续的存储单元 存放串值字符序列,但它们的存储空间是在程序执行过程中 动态分配而得。所以也称为动态存储分配的顺序表。在C语 言中,利用动态存储管理函数,来根据实际需要动态分配和 释放字符数组空间。 typedef char *string; //c中的串库相当于此类型定义
沈阳工业大学
数
据
结
构
与
算
法
串中任意个连续字符组成的子序列称为该串的子串 ,包含子串的串相应地称为主串。通常将子串在主串中 首次出现时的该子串的首字符对应的主串中的序号,定 义为子串在主串中的序号(或位置)。例如,设A和B分 别为 A=“This is a string” B=“is” 则B是A的子串,A为主串。B在A中出现了两次,其中首 次出现所对应的主串位置是3。因此,称B在A中的序号 (或位置)为3。 特别地,空串是任意串的子串,任意串是其自身的 子串。 通常在程序中使用的串可分为两种:串变量和串常 量。
数据结构(串)
数据结构(串)数据结构(串)数据结构中的串(String)是由字符构成的有限序列。
在计算机科学中,串是一种基本的数据结构,被广泛应用于字符串处理、文本搜索、模式匹配等领域。
1. 串的定义和基本操作串可以使用多种方式来定义和表示,常见的方式有:- 定长顺序存储表示:使用数组来存储串,数组的长度和最大串长相等,不足的部分用特定字符填充(通常用空格)。
- 堆分配存储表示:使用堆(动态内存分配区)来存储串,可以根据实际需要动态分配和释放串的存储空间。
- 串的块链存储表示:将串分成多个块,将每个块使用链表进行表示,将各块在一起组成完整的串。
串的基本操作包括:- 串的赋值:将一个串赋值给另一个串。
- 串的连接:将两个串按顺序连接成一个新的串。
- 串的比较:比较两个串的大小关系。
- 串的截取:从一个串中截取出一段子串。
- 串的插入:将一个串插入到另一个串的指定位置。
- 串的删除:删除一个串中指定位置的字符或一段子串。
- 串的替换:将一个串中指定位置的字符或一段子串替换成另一个串。
2. 串的匹配算法串的匹配是指在一个主串中查找一个模式串的过程。
常见的串匹配算法包括:- 朴素匹配算法:也称为暴力匹配算法,是最简单的匹配算法。
它从主串的第一个字符开始,与模式串逐个字符进行比较,若不匹配,则主串向后移动一位,直到找到匹配的子串或主串遍历完。
- KMP算法:即Knuth-Morris-Pratt算法,通过利用模式串自身的信息,减少字符的比较次数。
该算法具有线性时间复杂度,是一种高效的匹配算法。
- Boyer-Moore算法:基于模式串中的字符发生不匹配时的启发式策略,通过跳跃式地移动模式串,减少字符的比较次数,从而提高匹配效率。
3. 串的应用串作为一种基本的数据结构,在实际应用中具有广泛的用途,主要包括以下几个方面:- 字符串处理:串在文本编辑、编译器设计、语法分析、文件操作等方面都有广泛应用。
- 模式匹配:串的匹配算法常被用于字符串搜索、DNA序列分析、信息检索等领域。
KMP算法
KMP算法KMP算法是一种用于字符串匹配的快速算法,全称为Knuth-Morris-Pratt算法,是由Donald Knuth、Vaughan Pratt和James Morris在1977年共同提出的。
该算法的核心思想是通过利用已经匹配过的部分来避免不必要的字符比较,从而提高匹配效率。
1.暴力匹配算法在介绍KMP算法之前,我们先来了解一下暴力匹配算法。
暴力匹配算法,又称为朴素匹配算法,是最基本的匹配方法,它的思想就是从主串的第一个字符开始,逐个比较主串和模式串的字符,直到匹配成功或者主串和模式串的所有字符都比较完毕。
具体算法如下:```暴力匹配(主串S,模式串P):i=0j=0n = length(S)m = length(P)while i < n and j < m:if S[i] == P[j]: // 匹配成功,继续比较下一个字符i++else: // 匹配失败,模式串向后移动一位i=i-j+1j=0if j == m: // 匹配成功return i - jelse: // 匹配失败return -1```暴力匹配算法的时间复杂度为O(n*m),其中n和m分别为主串和模式串的长度。
2.KMP算法的思想KMP算法的关键在于构建一个部分匹配表,通过这个表来确定模式串在匹配失败时应该移动的位置。
部分匹配表的定义如下:对于模式串P的前缀子串P[0:i],如果存在一个真前缀等于真后缀,则称其长度为i的真前缀的真后缀长度为部分匹配值。
假设有一个模式串P,我们定义一个部分匹配表next,其中next[i]表示在P[i]之前的子串(不包括P[i])中,有多大长度的相同前缀后缀。
例如,P="ABCDABD",则next[7]=2,因为在P[7]之前的子串中,"ABD"是长度为3的前缀,也是长度为3的后缀。
构建部分匹配表的算法如下:构建部分匹配表(P):m = length(P)next = [0] * m // 初始化部分匹配表j=0k=-1next[0] = -1while j < m - 1:if k == -1 or P[j] == P[k]: // P[j]表示后缀的单个字符,P[k]表示前缀的单个字符j++k++next[j] = kelse:k = next[k]```构建部分匹配表的时间复杂度为O(m),其中m为模式串的长度。
数据结构_字符串操作原理
4.1 串类型的定义
一、串的基本概念
串(String)的定义
s=“a1a2…an”
其中:
s为串的名字, 串的值
ai(1≤i≤n)一般是字母、数学、标点符号等可屏幕显
示的字符。
串的长度n。
4.1 串类型的定义
字符串与一般的线性表的区别:
串的数据元素约束为字符集;
串的基本操作通常针对串的整体或串的一个部分进行。
3.串的某些操作(如:串的连接、串的替换等)受到限制。
4.2.2 堆分配存储表示
特点:
仍用一组连续的存储单元来存放串,但存储空间是在程序 执行过程中动态分配而得。 利用malloc函数合理预设串长空间。
typedef struct{ char *ch; int length; }HString;
子串和主串
eg:
A=“This is a string” B=“is”
特别地:
空串是任意串的子串,任意串是其自身的子串。
串的相等
二、串的抽象数据类型定义
ADT String{
数据对象:D={ai|ai∈CharacterSet,i=1,2,…,n;n≥0}
数据关系:S={< ai-1 , ai >| ai-1, ai ∈D, i = 2,…,n} 基本操作: StrAssign(&T,chars) StrLength(S) SubString(&Sub,S,pos,len) StrCopy(&T,S) Index(S,T,pos)
串的结束标志的设置
KMP算法(改进版)
4.3.2 模式匹配的一种改进算法这种改进算法是D.E.Knuth与V.R.Pratt和J.H.Morris同时发现的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。
此算法可以在O(n+m)的时间数量级上完成串的模式匹配操作。
其改进在于:每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
下面先从具体例子看起。
↓ i=3第一趟匹配 a b a b c a b c a c b a ba b c↑ j=3↓ i━━━━→3第二趟匹配a b a b c a b c a c b a ba b c a c↑━━→↑ j=5j=1 ↓ i━→ i=11第三趟匹配a b a b c a b c a c b a b(a)b c a c↑━→j=6回顾4.3的匹配过程示例,在第三趟的匹配中,当i=7、j=5字符比较不等时,又从i=4、j=1重新开始比较。
然后,经仔细观察可发现,在i=4和j=1,i=5和j=1以及i=6和j=1这三次比较都是不必进行的。
因为从第三趟部分匹配的结果就可以得出,主串中第4、5和6个字符必然是‘b’、‘c’和‘a’(即模式串中第2、3和4个字符)。
因为模式中的第一个字符是a,因此它无需再和这三个字符进行比较,而仅需将模式向右滑动三个字符的位置继续进行比较i=7、j=2的字符比较即可。
同理,在第一趟匹配中出现字符不等时,仅需将模式向右滑动两个字符的位置继续进行i=3、j=1时的字符比较。
由此,在整个匹配的过程中,i指针没有回溯,如图4.4所示。
现在讨论一般情况。
假设主串位‘s1s2…s n’,模式串为‘p1p2…p m’,从上例的分析可知,为实现改进算法,需要解决下述问题:当匹配过程中产生“失配”(即s i≠p j)时,模式串“向右滑动”可行的距离有多远,换句话说,当主串中第i个字符与模式中第j个字符“失配”(即比较不等)时,主串中第i个字符(i指针不回溯)应与模式中哪个字符再比较?假设此时应与模式中第k(k<j)个字符继续比较,则模式中前k-1个字符的字串必须满足下列关系式(4-2),且不可能存在k’>k,满足下列关系式(4-2)‘p1p2…p k-1’=‘s i-k+1s i-k+2…s i-1’ (4-2)而已经得到的“部分匹配”的结果是‘p j-k+1p j-k+2…p j-1’=’s i-k+1s i-k+2…s i-1’ (4-3)由(4-2)和(4-3)推得下列等式‘p1p2…p k-1’=‘p j-k+1p j-k+2…p j-1’ (4-4)反之,若模式串中存在满足式(4-4)的两个字串,则当匹配过程中,主串中第i个字符与模式中第j个字符比较不等时,仅需将模式向右滑动至模式中第k个字符和主串中第i个字符对齐,此时,模式中头k-1个字符的字串’p1p2…p k-1’必定与主串中第i个字符之前长度为k-1的字串’s i-k+1s i-k+2…s i-1’相等,由此,匹配仅需从模式中第k个字符与主串中第i个字符比较起继续进行。
KMP算法详解(超级详细)
KMP算法详解(超级详细)KMP算法,全称为Knuth-Morris-Pratt算法,是一种用于字符串匹配的快速算法。
它的核心思想是在匹配过程中,当出现不匹配的情况时,利用已经匹配的字符信息,避免进行重复匹配,从而提高匹配效率。
首先,我们需要了解一个重要的概念,"部分匹配值"(partialmatch table),它指的是字符串的前缀和后缀的最长的共有元素的长度。
例如,在字符串"ABCDABD"中,它的部分匹配值是[0, 0, 0, 0, 1, 2, 0]。
接下来,我们来详细了解KMP算法的实现过程:1.首先,针对模式串(被查找的字符串)进行预处理,得到部分匹配表。
-定义两个指针,i和j,分别指向模式串的开头和当前字符。
-初始化部分匹配表,将第一个元素置为0。
-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。
-若匹配,则将部分匹配表的下一个元素置为当前指针位置的下一个元素的值加1,并同时将当前指针和i都自增1-若不匹配且i>0,则将i更新为部分匹配表的前一个元素的值。
-若不匹配且i=0,则将当前指针自增1-循环结束后,部分匹配表得到构建。
2.匹配过程:-定义两个指针,i和j,分别指向需要匹配的文本和模式串的开头。
-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。
-若匹配,则将两个指针都自增1-若不匹配且j>0,则将j更新为部分匹配表的前一个元素的值。
-若不匹配且j=0,则将当前指针自增1-若模式串的指针j指向了最后一个字符,则说明匹配成功,返回匹配的位置。
-若循环结束仍未找到匹配的位置,则匹配失败。
总结一下,KMP算法可以分为两个步骤:预处理和匹配。
预处理的过程是构建部分匹配表,通过比较前缀和后缀的最长共有元素的长度,将这个长度记录在部分匹配表中。
匹配的过程是根据部分匹配表中的信息,来确定下一步的匹配位置,提高匹配的效率。
通过KMP算法,我们可以有效地解决字符串匹配问题,提高了匹配的效率。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
return OK;
}
Status Replace(SString S,SString T,SString V)
{ /* 初始条件: 串S,T和V存在,T是非空串(此函数与串的存储结构无关) */
/* 操作结果: 用V替换主串S中出现的所有与T相等的不重叠的子串 */
T[0]=S1[0]+S2[0];
return TRUE;
}
else
{ /* 截断S2 */
for(i=1;i<=S1[0];i++)
T[i]=S1[i];
for(i=1;i<=MAXSTRLEN-S1[0];i++)
{ /* 初始条件:串S存在。操作结果:将S清为空串 */
S[0]=0;/* 令串长为零 */
return OK;
}
Status Concat(SString T,SString S1,SString S2) /* 算法4.2改 */
{ /* 用T返回S1和S2联接而成的新串。若未截断,则返回TRUE,否则FALSE */
//////// 改进KMP算法
////////////////////////////////////////////////////////////////////////////////
S[i]=T[i-pos+1];
S[0]=MAXSTRLEN;
return FALSE;
}
}
Status StrDelete(SString S,int pos,int len)
{ /* 初始条件: 串S存在,1≤pos≤StrLength(S)-len+1 */
{
i=pos;
j=1;
while(i<=S[0]&&j<=T[0])
if(S[i]==T[j]) /* 继续比较后继字符 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
if(S[i]!=T[i])
return S[i]-T[i];
return S[0]-T[0];
}
int StrLength(SString S)
{ /* 返回串的元素个数 */
return S[0];
}
Status ClearString(SString S)
T[i]=S[i];
return OK;
}
Status StrEmpty(SString S)
{ /* 若S为空串,则返回TRUE,否则返回FALSE */
if(S[0]==0)
return TRUE;
else
return FALSE;
}while(i);
return OK;
}
void DestroyString()
{ /* 由于SString是定长类型,无法销毁 */
}
void StrPrint(SString T)
{ /* 输出字符串T。另加 */
int i;
for(i=1;i<=T[0];i++)
S[0]=S[0]+T[0];
return TRUE;
}
else
{ /* 部分插入 */
for(i=MAXSTRLEN;i<=pos;i--)
S[i]=S[i-T[0]];
for(i=pos;i<pos+T[0];i++)
串采用定长顺序存储结构的基本操作改进KMP算法
/*(程序名) */
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<malloc.h> /* malloc()等 */
#include<limits.h> /* INT_MAX等 */
/* 操作结果: 从串S中删除第pos个字符起长度为len的子串 */
int i;
if(pos<1||pos>S[0]-len+1||len<0)
return ERROR;
for(i=pos+len;i<=S[0];i++)
S[i-len]=S[i];
{ /* 初始条件: 串S和T存在,1≤pos≤StrLength(S)+1 */
/* 操作结果: 在串S的第pos个字符之前插入串T。完全插入返回TRUE,部分插入返回FALSE */
int i;
if(pos<1||pos>S[0]+1)
return ERROR;
}
int Index(SString S,SString T,int pos)
{ /* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0。 */
/* 其中,T非空,1≤pos≤StrLength(S)。算法4.5 */
int i,j;
if(1<=pos&&pos<=S[0])
{
StrDelete(S,i,StrLength(T)); /* 删除该串T */
StrInsert(S,i,V); /* 在原串T的位置插入串V */
i+=StrLength(V); /* 在插入的串V后面继续查找串T */
}
typedef char SString[MAXSTRLEN+1]; /* 0号单元存放串的长度 */
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
T[S1[0]+i]=S2[i];
T[0]=MAXSTRLEN;
return FALSE;
}
}
Status SubString(SString Sub,SString S,int pos,int len)
{ /* 用Sub返回串S的第pos个字符起长度为len的子串。算法4.3 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
/* c4-1.h 串的定长顺序存储表示 */
#define MAXSTRLEN 40 /* 用户可在255以内定义最大串长(1个字节) */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
for(i=1;i<=T[0];i++)
T[i]=*(chars+i-1);
return OK;
}
}
Status StrCopy(SString T,SString S)
{ /* 由串S复制得串T */
int i;
for(i=0;i<=S[0];i++)
//////// 串采用定长顺序存储结构的基本操作(14个)
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
int i;
if(pos<1||pos>S[0]||len<0||len>S[(i=1;i<=len;i++)
Sub[i]=S[pos+i-1];
Sub[0]=len;
return OK;
}
int StrCompare(SString S,SString T)
{ /* 初始条件: 串S和T存在 */
/* 操作结果: 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0 */
int i;
for(i=1;i<=S[0]&&i<=T[0];++i)
printf("%c",T[i]);
printf("\n");
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////