第4章查找

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

4.2.1 串的定长顺序存储表示
这种存储结构又称为串的顺序存储结构。是用一 组连续的存储单元来存放串中的字符序列。所谓定长顺 序存储结构,是直接使用定长的字符数组来定义,数组 的上界预先确定。 定长顺序存储结构定义为: #define MAX_STRLEN 256 typedef struct
{ char str[MAX_STRLEN] ; int length;
这样,串匹配问题可简化为找出某给定模式T在给定目 标串S中首次出现的有效位移。
算法实现
int IndexString(StringType s , StringType t , int pos ) /* 采用顺序存储方式存储主串s和模式t, */ /* 若模式t在主串s中从第pos位置开始有匹配的子串,*/ /* 返回位置,否则返回-1 */ { char *p , *q ; int k , j ; k=pos-1 ; j=0 ; p=s.str+pos-1 ; q=t.str ; /* 初始匹配位置设置 */ /* 顺序存放时第pos位置的下标值为pos-1 */
SubString (s, pos, len, sub) 初始条件:串s, 已存在, 1≦pos≦StrLength(s)且 0≦len≦StrLength(s) –pos+1。 操作结果:用sub返回串s的第pos个字符起长度为len 的子串。
……
} ADT String
4.2 串的存储表示和实现
/* 用T返回由s1和s2联结而成的串 */ { int k, j , t_len ;
if (T.ch) free(T); /* 释放旧空间 */ t_len=s1->length+s2->length ; if ((T.ch =(char *)malloc(sizeof((char)*t_len))==NULL)
每当一趟匹配过程出现字符不相等时,主串指示器不 用回溯,而是利用已经得到的“部分匹配”结果,将模式串 的指示器向右“滑动”尽可能远的一段距离后,继续进行比 较。
例:设有串s=“abacabab” ,t=“abab” 。则第一次
匹配过程如图4-2所示。
s=“a b a cbb” i=3
|| || || ≠
例如,设有串A和B分别是: A=“这是不是字符串”,B=“是”
则B是A的子串,A为主串。B在A中出现了2次,其中首次 出现所对应的主串位置是2。因此,称B在A中的序号为2 。
特别地,空串是任意串的子串,任意串是其自身的子串。
串相等:如果两个串的串值相等(相同),称这两个串 相等。换言之,只有当两个串的长度相等,且各个对应位置 的字符都相同时才相等。
}
4.2.2 串的堆分配存储表示
实现方法:系统提供一个空间足够大且地址连续的 存储空间(称为“堆”)供串使用。可使用C语言的动态 存储分配函数malloc()和free()来管理。
特点是:仍然以一组地址连续的存储空间来存储字 符串值,但其所需的存储空间是在程序执行过程中动态 分配,故是动态的,变长的。 串的堆式存储结构的类型定义
模式匹配是一个较为复杂的串操作过程。迄今为止,人 们对串的模式匹配提出了许多思想和效率各不相同的计算机 算法。介绍两种主要的模式匹配算法。
4.3.1 Brute-Force模式匹配算法
设S为目标串,T为模式串,且不妨设:
S=“s0s1s2…sn-1” , T=“t0t1t2 …tm-1” 串的匹配实际上是对合法的位置0≦i≦n-m依次将目标
else return(-1) ; /* 不匹配,返回-1 */ }
该算法简单,易于理解。在一些场合的应用里,如文 字处理中的文本编辑,其效率较高。
该算法的时间复杂度为O(n*m) ,其中n 、m分别 是主串和模式串的长度。通常情况下,实际运行过程中,该 算法的执行时间近似于O(n+m) 。
理解该算法的关键点
{ int k, j ; if (pos<0||pos>s.length-1||len<0||len>(s.length-pos)) return ERROR ; /* 参数非法 */ sub->length=len ; /* 求得子串长度 */ for (j=0, k=pos ; k<len+pos; k++, j++) sub->str[j]=s.str[i] ; /* 逐个字符复制求得子串 */ return OK ;
while (k<s.length)&&(j<t.length) { if (*p==*q) { p++ ; q++ ; k++ ; j++ ; } else { k=k-j+1 ; j=0 ; q=t.str ; p=s.str+k ; } /* 重新设置匹配位置 */ }
if (j==t.length) return(k-t.length) ; / * 匹配,返回位置 */
} StringType ;
1 串的联结操作
Status StrConcat ( StringType s, StringType t)
/* 将串t联结到串s之后,结果仍然保存在s中 */
{ int i, j ;
if ((s.length+t.length)>M联结后长度超出范围 */
◆ next域:存放指向下一结点的指针。 若每个结点仅存放一个字符,则结点的指针域就非
常多,造成系统空间浪费,为节省存储空间,考虑串结 构的特殊性,使每个结点存放若干个字符,这种结构称 为块链结构。如图4-1是块大小为3的串的块链式存储结 构示意图。
head
a bc
e pc
⋯⋯ g @ @ ⋀
图4-1 串的块链式存储结构示意图
T->ch[k]=s1->ch[j] ; /* 将串s2复制到串T中 */ free(s1->ch) ; free(s2->ch) ; return OK ; }
4.2.3 串的链式存储表示
串的链式存储结构和线性表的串的链式存储结构类 似,采用单链表来存储串,结点的构成是:
◆ data域:存放字符,data域可存放的字符个数称为 结点的大小;
4.3 串的模式匹配算法
模式匹配(模范匹配):子串在主串中的定位称为模式匹
配或串匹配(字符串匹配) 。模式匹配成功是指在主串S中 能够找到模式串T,否则,称模式串T在主串S中不存在。
模式匹配的应用在非常广泛。例如,在文本编辑程序 中,我们经常要查找某一特定单词在文本中出现的位置。显 然,解此问题的有效算法能极大地提高文本编辑程序的响应 性能。
串是一种特殊的线性表,其存储表示和线性表类似, 但又不完全相同。串的存储方式取决于将要对串所进行的 操作。串在计算机中有3种表示方式:
◆ 定长顺序存储表示:将串定义成字符数组,利用串 名可以直接访问串值。用这种表示方式,串的存储空间 在编译时确定,其大小不能改变。 ◆ 堆分配存储方式:仍然用一组地址连续的存储单元 来依次存储串中的字符序列,但串的存储空间是在程序 运行时根据串的实际长度动态分配的。 ◆ 块链存储方式:是一种链式存储结构表示。
typedef struct
{ char *ch; /* 若非空,按长度分配,否则为NULL */
int length; /* 串的长度 */
} HString ;
1 串的联结操作
Status Hstring *StrConcat(HString *T, HString *s1, HString *s2)
当第一次sk≠tj时:主串要退回到k-j+1的位置,而模式 串也要退回到第一个字符(即j=0的位置)。
比较出现sk≠tj时:则应该有sk-1=tj-1,…,sk-j+1=t1, sk-j=t0 。
4.3.2 模式匹配的一种改进算法
该改进算法是由D.E.Knuth ,J.H.Morris和
V.R.Pratt提出来的,简称为KMP算法。其改进在于:
{ printf(“系统空间不够,申请空间失败 !\n”) ; return ERROR ; }
for (j=0 ; j<s->length; j++) T->ch[j]=s1->ch[j] ; /* 将串s复制到串T中 */
for (k=s1->length, j=0 ; j<s2->length; k++, j++)
通常在程序中使用的串可分为两种:串变量和串常量。
串常量和整常数、实常数一样,在程序中只能被引用 但不能不能改变其值,即只能读不能写。通常串常量是由直 接量来表示的,例如语句错误(“溢出”)中“溢出”是直接 量。
串变量和其它类型的变量一样,其值是可以改变。
4.1.2 串的抽象数据类型定义
ADT String{ 数据对象:D = { ai|ai∈CharacterSet, i=1,2,…,n, n ≥0 } 数据关系:R = {<ai-1, ai>| ai-1, ai∈D, i=2,3,…,n } 基本操作:
串的块链式存储的类型定义包括: ⑴ 块结点的类型定义
#define BLOCK_SIZE 4 typedef struct Blstrtype
{ char data[BLOCK_SIZE] ; struct Blstrtype *next;
}BNODE ;
(2) 块链串的类型定义
typedef struct
4.1 串类型的定义
4.1.1 串的基本概念
串(字符串):是零个或多个字符组成的有限序列。记 作: S=“a1a2a3…”,其中S是串名,ai(1≦i≦n)是单个, 可以是字母、数字或其它字符。
串值:双引号括起来的字符序列是串值。 串长:串中所包含的字符个数称为该串的长度。 空串(空的字符串):长度为零的串称为空串,它不包 含任何字符。 空格串(空白串):构成串的所有字符都是空格的串称 为空白串。
串中的子串s[i…i+m-1]和模式串t[0…m-1]进行比较:
◆ 若s[i…i+m-1]=t[0…m-1]:则称从位置i开始 的匹配成功,亦称模式t在目标s中出现;
◆ 若s[i…i+m-1]≠t[0…m-1]:从i开始的匹配失 败。位置i称为位移,当s[i…i+m-1]=t[0…m-1]时, i称为有效位移;当s[i…i+m-1] ≠t[0…m-1]时,i 称为无效位移。
t=“a b a b”
j=3
匹配失败
图4-2 模式匹配示例
在i=3和j=3时,匹配失败。但重新开始第二次匹配 时,不必从i=1 ,j=0开始。因为s1=t1,t0≠t1,必有 s1≠t0,又因为t0=t2,s2=t2,所以必有s2=t0。由此可 知,第二次匹配可以直接从i=3 、j=1开始。
StrAssign(t , chars) 初始条件: chars是一个字符串常量。 操作结果:生成一个值为chars的串t 。
StrConcat(s, t) 初始条件:串s, t 已存在。
操作结果:将串t联结到串s后形成新串存放到s中。
StrLength(t) 初始条件:字符串t已存在。 操作结果:返回串t中的元素个数,称为串长。
注意:空串和空白串的不同,例如“ ”和“”分别表示长 度为1的空白串和长度为0的空串。
子串(substring):串中任意个连续字符组成的子序 列称为该串的子串,包含子串的串相应地称为主串。
子串的序号:将子串在主串中首次出现时的该子串的首 字符对应在主串中的序号,称为子串在主串中的序号(或位 置)。
for (i=0 ; i<t.length ; i++) s.str[s.length+i]=t.str[i] ; /* 串t联结
到串s之后 */
s.length=s.length+t.length ; /* 修改联结
后的串长度 */
return OK ;
}
2 求子串操作
Status SubString (StringType s, int pos, int len, StringType *sub)
{ BNODE head; /* 头指针 */
int Strlen ; /* 当前长度 */
} Blstring ; 在这种存储结构下,结点的分配总是完整的结点为
单位,因此,为使一个串能存放在整数个结点中,在串 的末尾填上不属于串值的特殊字符,以表示串的终结。
当一个块(结点)内存放多个字符时,往往会使操作 过程变得较为复杂,如在串中插入或删除字符操作时通 常需要在块间移动字符。
相关文档
最新文档