第4章 - 网络与云计算实验室
Download
Report
Transcript 第4章 - 网络与云计算实验室
数据结构---串
齐 恒
[email protected]
大黑楼 B0912
中国互联网发展状况
中国网民数量有多少?
中国互联网发展状况
在网上干什么?
• QQ?微信?
• 看新闻?
• 查资料?
• 听音乐?
• 看视频?
• 玩微博?
• 购物?
在网上干什么?
全球网民在干什么?
在互联网中,信息搜索引擎的
应用是最为广泛的
拉里·佩奇(Larry Page)
•Google搜索引擎源于拉里·佩奇和谢尔盖·布林在斯坦福大学读书时所做的一个研究项目。他们最
开始是在佩奇简陋的宿舍搞研究。
•1996年初,佩奇和布林开始合作研究一名为“BackRub”的搜索引擎,到1998年上半年逐步完
善这项技术后,两人开始为这项技术寻找合作伙伴。他们找到雅虎的创始人之一戴维·菲洛。菲洛
认为他们的技术确实很可靠,但建议他们自己建立一个搜索引擎公司发展业务,发展起来后再考虑
合作。
信息检索技术
信息检索(Information retrieval, IR)是指将信息按照
一定的方式组织和存储起来,并根据信息用户的需求找
出有关的信息的过程和技术。它的全称应该叫“信息存
储与检索”(Information Storage and Retrieval)。
信息存储:对信息进行特征描述、加工并使其有序化。
基础
目的
信息检索:借助一定的设备和工具,采用一系列方法
和策略查找出所需要的信息。
狭义的信息检索指的是后一过程.
信息检索历史
单机批处理检索阶段 :
1946年,世界上第一台数字式电子计算机诞生,1951年,美国麻省理工学院
开始对利用计算机代码化文摘进行可行性研究。 这一阶段也称为脱机检索时
期,一是单机由专人操作;二是只能进行批处理不能即问即答。
联机检索阶段:
1960年,美国国家医学图书馆开始建立“医学文献分析与检索系统”。
网络化检索阶段:
20世纪80年代中期,美国国家科学基金会计算机网络(NSFnet)将各地的一
些大学、科研机构及政府机构的局域网络联结成一个全国性的计算机信息网
络 。进入90年代,世界各国在仿效NSFnet建立全国性文献信息计算机网络基
础上,设法与美国联网,因而产生了国际计算机互联网络——Internet。
Internet搜索引擎历史
• 1990年,加拿大麦吉尔大学(University of McGill)计算机学院的师生开发出
Archie,查找FTP主机中的文件。Archie被公认为现代搜索引擎的鼻祖.
• 1993年MIT大学的Matthew Gray开发了 World Wide Web Wanderer,这是第一
个利用HTML网页之间的链接关系来检测万维网规模的"机器人(Robot)"程序.
开始,它仅仅用来统计互联网上的服务器数量,后来也能够捕获网址(URL).
• 1994年4月,斯坦福大学(Stanford University)的两名博士生,美籍华人Jerry
Yang(杨致远)和David Filo共同创办了Yahoo。
• 1994年初,华盛顿大学(University of Washington )的学生Brian Pinkerton
开始了他的小项目WebCrawler。它是互联网上第一个支持搜索文件全部文字
的全文搜索引擎。
• 1994年7月,卡内基·梅隆大学(Carnegie Mellon University) 的Michael
Mauldin创建了Lycos。Lycos第一个在搜索结果中使用了网页自动摘要,而最
大的优势还是它远胜过其它搜索引擎的数据量。
• 1994年底,Infoseek正式亮相.其友善的界面,大量的附加功能,使之和Lycos一
样成为搜索引擎的重要代表。
Internet搜索引擎历史
• 1995年,一种新的搜索引擎形式出现了——元搜索引擎(A Meta Search
Engine Roundup)。第一个元搜索引擎,是Washington大学硕士生 Eric
Selberg 和 Oren Etzioni 的 Metacrawler.
• 1995年12月,DEC的正式发布AltaVista。AltaVista是第一个支持自然语言搜
索的搜索引擎,第一个实现高级搜索语法的搜索引擎(如 AND, OR, NOT等)。
• 1997年8月,Northernlight搜索引擎正式现身.它曾是拥有最大数据库的搜索
引擎之一。
• 1998年10月之前,Google只是斯坦福大学(Stanford University)的一个小项
目BackRub。1995年博士生Larry Page开始学习搜索引擎设计,于1997年9月15
日注册了google.com的域名,1997年底,在Sergey Brin和Scott Hassan,Alan
Steremberg的共同参与下,BachRub开始提供Demo。
• 1999年2月,Google完成了从Alpha版到Beta版的蜕变.Google公司则把1998年9
月27日认作自己的生日。2006年4月,Google宣布其中文名称“谷歌”,这是
Google第一个在非英语国家起的名字。
国内Internet搜索引擎历史
• 1996年8月,sohu公司成立,制作中文网站分类目录,曾有"出门找地图,上网找
搜狐"的美誉.随着互联网网站的急剧增加,这种人工编辑的分类目录已经不适
应.
• 1998年1月,台湾中正大学吴升教授所领导的GAIS实验室创立了Openfind搜索
引擎。Openfind起先只做中文搜索引擎,鼎盛时期同时为三大著名门户新浪,
奇摩,雅虎提供中文搜索引擎。
• 2000年1月,两位北大校友,超链分析专利发明人,前Infoseek资深工程师李彦
宏与好友徐勇(加州伯克利分校博士后)在北京中关村创立了百度 (Baidu)公
司。
• 2001年8月发布Baidu.com搜索引擎Beta版(此前Baidu只为其它门户网站搜狐
新浪Tom等提供搜索引擎),2001年10月22日正式发布Baidu搜索引擎,专注于中
文搜索。2005年8月5日在纳斯达克上市, 创下了5年以来美国股市上市新股当
日涨幅最高纪录。
词袋模型(bag-of-words)
文本信息检索中的索引机制
--- 词袋模型(bag-of-words model, BoW)
--- 倒排文件索引(inverted file)
词汇表
Word 1
Word 2
Word 3
Word n
词袋模型示例
Internet
网页的BoW表示
构建倒排文件
网络
网络
文档 1
文档 2
…
云计算
文档 1
文档 5
…
实验室
文档1
文档 2
…
检索条件的BoW表示
云计算
实验室
第四章
串
4.1 串的相关术语
4.2 串的抽象数据类型的定义
4.3 串的表示和实现
4.4 串的模式匹配算法
4.1 串的相关术语
1. 串是普遍存在的数据对象
人名,地名,货物名,…
文字编辑中的各种字符
信息检索和问答系统中的输入信息
源程序,目标程序
2. 串的定义
由零个或多个字符组成的有限序列.
一般记为:s= a1a2…an ,n>=0
串名:s => 变量名 => 字符串
串值: a1a2…an
=〉空格串: a1,a2,…,an 均为空格
串长:n => n=0 =〉空串
空格串不同于空串
子串:串中任意个连续的字符组成的
子序列
=〉原串:主串
位置:字符的位置,子串的位置
串相等:当且仅当两个串的串值相等
4.2 串的抽象数据类型的定义如下:
ADT String {
数据对象:
D={ ai | ai∈CharacterSet,
i=1,2,...,n,
n≥0 }
数据关系:
R1={ < ai-1, ai > | ai-1, ai ∈D,
i=2,...,n }
基本操作:
StrAssign (&T, chars)
DestroyString(&S)
StrCopy (&T, S)
StrLength(S)
StrCompare (S, T)
Concat (&T, S1, S2)
StrEmpty (S)
SubString (&Sub, S, pos, len)
ClearString (&S)
Index (S, T, pos)
Replace (&S, T, V)
StrInsert (&S, pos, T)
StrDelete (&S, pos, len)
} ADT String
StrAssign (&T, chars)
初始条件:chars 是字符串常量。
操作结果:T赋值为 chars 的值。
StrCopy (&T, S)
初始条件:串 S 存在。
操作结果:由串 S 复制得串 T。
DestroyString (&S)
初始条件:串 S 存在。
操作结果:串 S 被销毁。
StrEmpty(S)
初始条件:串S存在。
操作结果:若 S 为空串,则返回TRUE,
否则返回 FALSE。
注: 表示空串,其长度为0。
StrCompare(S,T)
初始条件:串 S 和 T 存在。
操作结果:若S T,则返回值 0
若S T,则返回值 0
若S T,则返回值 0
比较原则:按字母顺序,逐位比较
实际上是按ASCII码顺序比较
例如:StrCompare(data, state) < 0
StrCompare(cat, case) > 0
StrCompare(cat, cat) = 0
StrLength (S)
初始条件:串 S 存在。
操作结果:返回 S 的元素个数,
称为串的长度。
注:空格在串中占一个位置,
其长度为1。
Concat (&T, S1, S2)
初始条件:串 S1 和 S2 存在。
操作结果:用 T 返回由 S1 和 S2
联接而成的新串。
例如: Concat( T, man, kind)
求得 T = mankind
SubString (&Sub, S, pos, len)
初始条件:
串 S 存在,1≤pos≤StrLength(S)
且0≤len≤StrLength(S)-pos+1。
操作结果:
用 Sub 返回串 S 的第 pos 个字符起
长度为 len 的子串。
子串为“串”中的一个字符子序列
例如:
SubString( sub, commander, 4, 3)
求得 sub = man ;
SubString( sub, commander, 1, 9)
求得 sub = commander;
SubString( sub, commander, 9, 1)
求得 sub = r;
SubString(sub, commander, 4, 7)
sub = ?
SubString(sub, beijing, 8, 2) = ?
sub = ?
起始位置和子串长度之间存在约束关系
SubString(student, 5, 0) =
长度为 0 的子串为“合法”串
Index(S,T,pos)
初始条件:串S和T存在,T是非空串,
1≤pos≤StrLength(S)。
操作结果: 若主串 S 中第pos个字符之后
存在和串 T 值相同的子串, 则
返回它在主串 S 中第pos个字符
之后第一次出现的位置;
否则函数值为0。
“子串在主串中的位置”意指子串
中的第一个字符在主串中的位序。
假设 S = abcaabcaaabc, T = bca
Index(S, T, 1) = 2;
Index(S, T, 3) = 6;
Index(S, T, 8) = 0;
Replace(&S, T, V)
初始条件:串S, T和 V 均已存在,
且 T 是非空串。
操作结果:用V替换主串S中出现
的所有与(模式串)T
相等的不重叠的子串。
例如:
假设 S = abcaabcaaabca,T = bca
若 V = x, 则经置换后得到
S = axaxaax
若 V = bc, 则经置换后得到
S = abcabcaabc
StrInsert (&S, pos, T)
初始条件:串S和T存在,
1≤pos≤StrLength(S)+1。
操作结果:在串S的第pos个字符之前
插入串T。
例如:S = chater,T = rac,
则执行 StrInsert(S, 4, T)之后得到
S = character
StrDelete (&S, pos, len)
初始条件:串S存在
1≤pos≤StrLength(S)-len+1。
操作结果:从串S中删除第pos个字符
起长度为len的子串。
ClearString(&S)
初始条件:串S存在。
操作结果:将S清为空串。
对于串的基本操作集可以有不同
的定义方法。
在使用高级程序设计语言中的串
类型时,应以该语言的参考手册为准。
例如:
标准C语言函数库string.h中,
提供下列串处理函数
gets(str) :输入一个串;
puts(str) :输出一个串;
strcat(str1, str2) :串联接函数;
strcpy(str1, str2) :串复制函数;
strcmp(str1, str2) :串比较函数;
strlen(str) :求串长函数;
在上述抽象数据类型定义的13种操作中,
串赋值StrAssign、 串比较StrCompare、
求串长StrLength、串联接Concat以及求
子串SubString
五种操作构成串类型的最小操作子集。
即:利用这些操作可以实现字符串的所有操作
(ClearString和DestroyString除外)。
例如,可利用串比较、求串长和求子串等
操作实现定位函数Index(S,T,pos)。
算法的基本思想为:
StrCompare(SubString(S, i, StrLength(T)),T )
?0
int Index (String S, String T, int pos) {
// T为非空串。若主串S中第pos个字符之后存在与 T相等的子串,则返回第一个
这样的子串在S中的位置,否则返回0
if (pos > 0) {
n = StrLength(S); m = StrLength(T); i = pos;
while ( i <= n-m+1) {
SubString (sub, S, i, m);
if (StrCompare(sub,T) != 0) ++i ;
else return i ;
} // while
} // if
return 0;
// S中不存在与T相等的子串
} // Index
又如串的置换函数:
i
S串
sub1
T串
V串
new 串
sub1
V串
sub2
串的逻辑结构和线性表极为相似,区别
仅在于串的数据对象限定为字符集。
串的基本操作和线性表有很大差别。
在线性表的基本操作中,大多以“单个
元素”作为操作对象;
在串的基本操作中,通常以“串的整体”
或子串作为操作对象。
4.3 串的表示和实现
在程序设计语言中,串只是作为输
入或输出的常量出现,则只需存储此串
的串值(即字符序列)即可。但在多数
非数值处理的程序中,串也以变量的形
式出现。
一、串的定长顺序存储表示
二、串的堆分配存储表示
三、串的块链存储表示
一、串的定长顺序存储表示
按照预先定义的大小,为每个
串变量分配一个固定长度的存储区
(一组地址连续的存储单元,用以
存储串值)
#define MAXSTRLEN 255
// 用户可在255以内定义最大串长
typedef unsigned char Sstring
[MAXSTRLEN + 1];
// 0号单元存放串的长度
串的实际长度可在这个预定义长
度的范围内随意设定,超过预定义
长度的串值则被舍去,称之为
“截断” 。
按这种串的表示方法实现的串的
运算时,其基本操作为 “字符序列
的复制”。
例如:串的联接算法中需分三种情况处理:
Status Concat(SString S1, SString S2, SString &T) {
// 用T返回由S1和S2联接而成的新串。若未截断, 则返回TRUE,否则FALSE。
if (S1[0]+S2[0] <= MAXSTRLEN) {// 未截断
T[1..S1[0]] = S1[1..S1[0]];
else if (S1[0] <MAXSTRSIZE) { // 截断s2
T[S1[0]+1..S1[0]+S2[0]] = S2[1..S2[0]];
T[1..S1[0]]
=
S1[1..S1[0]];
T[0]else
= S1[0]+S2[0];
uncut = TRUE; }
{ // 截断S1,并舍弃s2
T[S1[0]+1..MAXSTRLEN] =
T[0..MAXSTRLEN] = S1[0..MAXSTRLEN];
S2[1..MAXSTRLEN-S1[0]];
// T[0] == S1[0] == MAXSTRLEN
T[0] = MAXSTRLEN; uncut = FALSE; }
uncut = FALSE;
}
return uncut;
} // Concat
二、串的堆分配存储表示
为每个串变量动态分配一个存储区,
该存储区称为“堆”(heap),也是一组
地址连续的存储单元,用以存储串值。
利用C语言的动态分配函数malloc()和
回收函数free()管理堆。
约定:串长也要存储
基本操作:仍为 “字符序列的复制”
结构定义:
typedef struct {
char *ch;
// 若是非空串,则按串长分配存储区,
// ch指向首地址,否则为NULL
int length; // 串长度
} HString;
特点:串长不受限制,较为灵活。
C语言中的串以一个‘\0’为结束符,
串长是一个隐含值。
这类串操作实现的算法为:
先为新生成的串分配一个存储空间,
然后进行串值的复制。
Status Concat(HString &T, HString S1, HString S2)
{ // 用T返回由S1和S2联接而成的新串
if (T.ch) free(T.ch);
// 释放旧空间
if (!(T.ch = (char *)
malloc((S1.length+S2.length)*sizeof(char))))
exit (OVERFLOW);
T.length = S1.length + S2.length;
T.ch[0..S1.length-1] = S1.ch[0..S1.length-1];
T.ch[S1.length..T.length-1] = S2.ch[0..S2.length-1];
return OK;
} // Concat
Status SubString(HString &Sub, HString S,
int pos, int len) {
// 用Sub返回串S的第pos个字符起长度为len的子串
if (pos < 1 || pos > S.length || len < 0
|| len > S.length-pos+1)
return ERROR;
if (Sub.ch) free (Sub.ch);
// 释放旧空间
if (!len)
{ Sub.ch = NULL; Sub.length = 0; } // 空子串
else
// 求完整子串
{
Sub.ch = (char *)malloc(len*sizeof(char));
Sub.ch[0..len-1] = S[pos..pos+len-1];
Sub.length = len;
}
return OK;
} // SubString
三、串的块链存储表示
可用链表(块+链)来存储串值。由于串的
数据元素是一个字符( 8 位二进制数),
因此 ,用链表存储时,通常一个结点中
存放的不是一个字符,而是一个子串。
空间填补:用“#”填补最后一个结点
#define CHUNKSIZE 80 // 可由用户定义的块大小
typedef struct Chunk { // 结点块结构
char ch[CUNKSIZE];
struct Chunk *next;
} Chunk;
typedef struct { // 串的链表结构
Chunk *head, *tail; // 串的头和尾指针
int curlen; // 串的当前长度
} LString;
实际应用时,可以根据问题所需来
设置结点的大小。
例如: 在编辑系统中,整个文本编辑区
可以看成是一个串,每一行是一个子串,
构成一个结点。即: 同一行的串用定长结构
(80个字符), 行和行之间用指针相联接。
4.4 串的模式匹配算法
这是串的一种重要操作,很多
软件,若有“编辑”菜单项的话,
则其中必有“查找”子菜单项。
首先,回忆一下串匹配(查找)的定义:
INDEX (S, T, pos)
初始条件:串S和T存在,T是非空串,
1≤pos≤StrLength(S)。
操作结果:若主串S中第pos个字符之后
存在和串T值相同的子串
返回它在主串S中第pos个
字符之后第一次出现的位置;
否则函数值为0。
下面讨论以定长顺序结构表示串时
的几种INDEX (S, T, pos)算法
一、简单算法
二、首尾匹配算法
三、KMP算法
(D.E.Knuth,J.H.Morris ,V.R.Pratt)
一、简单匹配算法
算法思想:
从主串S的第pos个字符起,和模式
串T的第一个字符相比较,如相同,则继
续比较后续字符,否则从主串的下一个
字符起,再重新和模式串的字符相比较,
依次类推,直至模式串T中的每个字符依
次与主串S中的一个连续字符序列相等,
则称匹配成功,否则称匹配不成功。
例:S=‘ababcabcacbab’,
T=‘abcac’,
求INDEX(S, T, 1)
简单匹配算法:6趟扫描
int Index(SString S, SString T, int pos) {
// 返回子串T在主串S中第pos个字符之后的位置。若不存在,
// 则函数值为0。其中,T非空,1≤pos≤StrLength(S)。
i = pos; j = 1;
while (i <= S[0]-T[0]+1 && j <= T[0]) {
if (S[i] == T[j]) { ++i; ++j; } // 继续比较后继字符
else { i = i-j+2; j = 1; } // 指针后退,重新匹配 }
if (j > T[0]) return i-T[0];
else return 0;
} // Index
时间复杂度:o(n*m)
二、首尾(同时)匹配算法
先比较模式串的第一个字符,
不相等,则找主串下一位置,
如相等,再比较模式串的最后一个字符,
不相等,则找主串下一位置,
如相等,再按上述方法,继续比较模式
串中从第二个到第n-1个字符。
int Index_FL(SString S, SString T, int pos) {
i = pos; j = 1; m=i+T[0]-1; n=T[0]
while (i <= S[0]-T[0]+1 && j <= T[0]/2 ) {
if (S[i] == T[j] && S[m]= =T[n])
{ ++i; ++j; --m; --n;} // 继续比较后继字符
else
{ i = i-j+2; j = 1; m=i+T[0]-1; n=T[0]}
// 指针后退,重新匹配 }
if (j > T[0]/2 ) return i-T[0];
else return 0;
时间复杂度:o(n*m)
} // Index
例:S=‘ababcabcacbab’, T=‘abcac’,
求INDEX(S, T, 1)
首尾匹配算法:6趟扫描, 但是单个
字符比较次数有所减少
三、KMP算法
(D.E.Knuth,J.H.Morris,V.R.Pratt)
KMP算法的时间复杂度可以达到O(m+n)
问题:当 S[i] T[j] ,出现不匹配时,
S[i]是否可以不回溯?如果可以?
S[i]应和T的那个字符继续比较?
i
例:S: abcabbabcabbabd,
T: abcabbabd
j
j
不失一般性地,当 S[i] T[j] 时,
已经得到的结果是:
T[1..j-1] = S[i-j+1..i-1]
若使i不回溯,则应使S[i] 和某个 T[k]
相比较(k<j),
则应有: T[1..k-1] = S[i-k+1..i-1]
因已有: T[j-k+1..j-1] = S[i-k+1..i-1]
则应有: T[1..k-1] = T[j-k+1..j-1]
反之,如果有: T[1..k-1] = T[j-k+1..j-1]
则S[i] 可以和 T[k]比较,继续匹配过程
S: S1…Si-j+1Si-j+2 …………
T:
Si-k+1 … Si-1 Si …
T1 T2 … T k-1 Tk …Tj-k+1… Tj-1Tj
当S[i]T[j]时,i, j变化规律:
1)当T[1]不匹配时,应设置++i , j=1 ,
从主串下一字符继续比较;
2)当存在T[1..k-1] = T[j-k+1..j-1],则S[i]
应和(最大的) T[k]比较(i不变,
j=k = next[j]), 继续比较;
3) 其他情况, i不变,j=1, 继续比较
模式串的next[j]函数:
j的下一位置k
当j 1时
0
Max{k | 1 k j
next[j]
… p '}
…
且
'
p
p
p
'
'
p
1 2
k-1
j-k 1
j-1
1
其它情况
int Index_KMP(SString S, SString T, int pos) {
// 1≤pos≤StrLength(S)
i = pos; j = 1;
while (i <= S[0] && j <= T[0]) {
if (j = 0 || S[i] == T[j]) { ++i; ++j; }
// 继续比较下一字符
else j = next[j];
// 模式串向右移动
}
if (j > T[0]) return i-T[0]; // 匹配成功
else return 0;
时间复杂度: O(n)
} // Index_KMP
如何求next[j]函数值 =〉递推过程
分析如下:
已知: next[1] = 0, next[j] = k,求next[j+1]
=〉T[1..k-1] = T[j-k+1..j-1]
如果: T[j] = T[k]=〉T[1..k] = T[j-k+1..j]
则: next[j+1]= k+1=〉next[j+1]=next[j]+1
若: T[j] T[k],则需往前回朔,比较
T[j] 是否等于 T[ next[k]]
这实际上也是一个匹配的过程,
不同在于:主串和模式串是同一个串
可以仿造KMP算法,求next[j+1]
void get_next(SString &T, int &next[] ) {
// 求模式串T的next函数值并存入数组next
i = 1; next[1] = 0; j = 0;
while (i < T[0]) {
if (j = 0 || T[i] = = T[j])
{ ++i; ++j; next[i] = j; }
else j = next[j];
j
}
模式
} // get_next
时间复杂度:
O(m)
123456 78
abaabc ac
Next[j] 0 1 1 2 2 3 1 2
还有一种特殊情况需要考虑:
= aaabaaaab
T = aaaab
例如: S
next[1..5]=0 1 2 3 4,
问题:有些比较是多余的,需改进
方法:用nextval[i] 代替next[i]
void get_nextval(SString &T, int &nextval[]) {
i = 1; nextval[1] = 0; j = 0;
while (i < T[0]) {
if (j = 0 || T[i] == T[j]) {
++i; ++j;
if (T[i] != T[j]) nextval[i] = j;
else nextval[i] = nextval[j]; }
else j = nextval[j];
}
时间复杂度:
} // get_nextval
O(m)
计算nextval[j]的方法:
(1)按照算法进行求解;
(2) 先计算出next[j],再计算nextval[j].
例:
T = aaaab
next[1..5]=0 1 2 3 4
nextval[1..5]=0 0 0 0 4
KMP算法总结
1. 关于next[j]函数的含义:当主串的S[i]与模式串
的T[j]比较而不相等时,next[j]指示应与S[i] 继续比较
的模式串的下一位置
a) 如果T[1] S[i] ,则应使 i=i+1, j=1, 使S[i]与模式
串的T[1]继续比较, 因此此时有next[j]=0, ;
b) 如果有T[1..k-1] = T[j-k+1..j-1] ,则next[j]=k, i不
变,使S[i]与模式串的T[k]( 即T[next[j]])继续比较;
c) 如果j 1 且没有T[1..k-1] = T[j-k+1..j-1] ,此时i
应不变, j=1, S[i]应与模式串的T[1]继续比较,因此有
next[j]=1。
2. 关于next[j]函数的计算=〉递推过程
已知: next[1] = 0, next[2]=1, next[j] = k , 求
next[j+1]
分析求解:
next[j] = k
T[1..k-1] = T[j-k+1..j-1]
1)如果: T[j] = T[k]=〉T[1..k] = T[j-k+1..j]
则: next[j+1]= k+1=〉next[j+1]=next[j]+1
i=i+1
2)如果: T[j] T[k],此时可将T既当成模式串,
又当成主串
=〉 T[j] 应与 T[next[k]](T[k’])相比较
a) 若T[j] = T[k’]=〉T[1..k’] = T[j-k’+1..j]
则: next[j+1]= k’+1=〉next[j+1]=next[k]+1
b) 若T[j] T[k’]=〉T[j] 应与 T[next[k’]]
(T[k’’])相比较,重复与a)类似的过程 ……
c) 若不存在任何k* (1<k*<j), 满足T[1..k*] =
T[j-k*+1..j],则next[j+1]=1
3. 关于nextval[j]函数的含义
一般情况下,当next[j]=k, 意味着如果主串
S[i] T[j],则S[i]应与模式串的T[k]继续比较。
但是如果T[j]=T[k],则S[i]不必与模式串的
T[k]比较,而应与模式串的T[next[k]]继续比较.
本章学习要点
1. 熟悉串的七种基本操作的定义,
并能利用这些基本操作来实现串的
其它操作的方法。
2. 掌握在串的定长顺序存储结构、
堆存储结构、块链存储结构上实现串
的各种操作的方法。
3*. 理解串模式匹配KMP算法的基本
原理,掌握NEXT函数的定义,学会手
工计算给定模式串的Next[j]函数值
和改进的Nextval[j]函数值。
4. 了解串操作的应用方法和特点。
习题:
设 主 串 S=‘abcaaabcaaabcaaabcaabc’ ,
模式串T=‘abcaaabcaab’,
(1)求出模式T的Next[j]值;
(2)求出模式T的NextVal[j]值;
(3)在S中查找T至少需要几趟匹配?至少需
要几次比较?请给出详细的匹配过程。
第二章
1、顺序线性表与链式线性表的区别
2、链表的操作(插入、删除)
3、链式结构实现一元多项式
第三章
1、栈和队列的特点
2、栈的典型应用
3、栈和递归
第四章
1、串的概念
2、串的模式匹配算法
3、重点掌握KMP算法