1、1,第四章 串,4.1 串类型的定义,4.2 串的表示和实现,4.3 串的模式匹配算法,2,4.1 串类型的定义 一、串的基本概念 1.串即字符串,是由零个或多个字符组成的有限序列,是数据元素为单个字符的特殊线性表。,3,串与线性表 串的逻辑结构和线性表极为相似,区别仅在于串的数据对象约束为字符集。 串的基本操作和线性表有很大差别。 在线性表的基本操作中,大多以“单个元素”作为操作对象; 在串的基本操作中,通常以“串的整体”作为操作对象。,4,基本操作:,StrAssign ( &T, chars ),StrCopy ( &T, S ),DestroyString ( &S ),StrEmpt
2、y ( S ),StrCompare ( S, T ),Index ( S, T, pos ),StrLength ( S ),SubString ( &Sub, S, pos, len ),Concat ( &T, S1, S2 ),StrInsert ( &S, pos, T ),Replace ( &S, T, V ),ClearString ( &S ),StrDelete ( &S, pos, len ),5,串的基本操作示例:,6,gets(str) / 输入一个串;puts(str) / 输出一个串;strcat(str1, str2) / 串联接函数;strcpy(str1,
3、str2, k) / 串复制函数;strcmp(str1, str2) / 串比较函数;strlen(str) / 求串长函数;,C 语言字符串函数库中提供下列串处理函数: 头文件:# include ,7,4.2 串的表示和实现,一、定长顺序存储表示,用一组地址连续、长度固定的存储单元存储串值的字符序列。 当串的实际长度大于存储区的长度时,超过部分的串值则被舍去,称为“截断”。,串长的标识方法: 方法1:用下标为0的分量存放串长; 方法2:在串值后面加入结束标记符(0)。(C/C+语言),8,#define MAXSTRLEN 255 / 串的“定长” typedef unsigned ch
4、ar SstringMAXSTRLEN + 1; / Sstring0 存放串的长度,串的定长顺序存储结构的C语言描述,特点:串的实际长度可在这个定长的范围内随意设定;实现串的运算时,基本操作为字符序列的复制,9,二、堆分配存储表示,用一组地址连续的存储单元存储串值的字符序列,但存储空间是在程序执行过程中动态分配而来。 这种存储结构中,基本操作和定长表示相同,仍然是基于“字符序列的复制”。 在堆存储分配中无须考虑“截断”问题。 在堆分配的存储表示中,存储空间的管理成为算法实现所关心的重要问题,特别是对于新分配空间的大小的计算和存储空间的释放。,10,typedef struct char *c
5、h; / 若是非空串,则按串长分配存储区,/ 否则不分派存储区,ch为NULLint length; / 串长度 HString;,串的堆分配存储结构的C语言描述,11,通常,C语言中提供的串类型就是以这种存储方式实现的。 系统利用函数malloc( ) 和 free( ) 进行串值空间的动态管理,为每一个新产生的串分配一个存储区,称串值共享的存储空间为“堆”。C语言中的串以一个空字符为结束符,串长是一个隐含值。 这类串操作实现的算法为: 先为新生成的串分配一个存储空间,然后进行串值的复制。,12,三、块链存储表示,用链表存储串,通常一个结点中存放的不是一个字符,而是一个子串。每个结点分配定长
6、的存储空间(块),最后一个结点可能未满,通常用 # 进行填充。,设立头指针和尾指针,并给出串的长度,这种结构称为“块链结构”。,13,9/15=3/5,1/2,讨论:法1存储密度为 ;法2存储密度为 ;,显然,若数据元素很多,用法2存储更优称为块链结构.,法1:链表结点(数据域)大小取1,法2:链表结点(数据域)大小取n(例如n=4),14,#define CHUNKSIZE 80 / 可由用户定义的块大小typedef struct Chunk / 结点结构char chCUNKSIZE;struct Chunk *next; Chunk;,块链存储结构的C语言描述,typedef stru
7、ct / 串的链表结构Chunk *head, *tail; / 串的头和尾指针int curlen; / 串的当前长度 LString;,15,实际应用时,可以根据问题所需来设置结点的大小。 例如,在编辑系统中,整个文本编辑区可以看成是一个串,每一行是一个子串,构成一个结点。即: 同一行的串用定长结构, 行和行之间用指针相联接。,块链结构的缺点: 由于串的应用需要经常对字符或者子串进行随机访问,链表的结构明显不适合这种应用。 另外,对于跨越多个结点的子串的操作,链表的操作就不如顺序结构灵活。 块链的构造也成为算法设计中费神的问题:结点的大小究竟为多少才合适?,16,第五章 数组和广义表,5.
8、1 数组的类型定义,5.3 矩阵的压缩存储,5.2 数组的顺序表示和实现,5.4 广义表的类型定义,5.5 广义表的存储结构,17,数组和广义表的特点:一种特殊的线性表 元素的值并非原子类型,可以再分解,表中元素也是一个线性表(即广义的线性表)。 所有数据元素仍属同一数据类型。,18,5.1 数组的定义,一、数组的基本概念 数组:由一组名字相同、下标不同的变量构成。,注意: 本章所讨论的数组与高级语言中的数组有所区别:高级语言中的数组是顺序结构;而本章的数组既可以是顺序的,也可以是链式结构,用户可根据需要选择。,19,二维数组的特点:,一维数组的特点:,1个下标,ai是ai+1的直接前驱,2个
9、下标,每个元素ai,j受到两个关系(行关系和列关系)的约束,一个mn的二维数组可以看成是m行的一维数组,或者n列的一维数组。,N维数组的特点:,n个下标,每个元素受到n个关系约束,20,二、数组的抽象数据类型定义 ADT Array 数据对象:Daj1,j2, .,jn| ji =0,.,bi -1, i=1,2,n n 称为数组的维度,bi 是数组第 i 维的长度数据关系:RR1, R2, ., RnRi | 0 jk bk -1, 1 k n 且k i, 0 ji bi -2, i=2,.,n ADT Array,基本操作:,21,二维数组的定义:,数据对象:D = aij | 0ib1-
10、1, 0 jb2-1 数据关系:R = ROW, COL ROW=|0ib1-1, 0jb2-2COL=|0ib1-2, 0jb2-1,22,基本操作: InitArray(&A, n, bound1, ., boundn) DestroyArray(&A) Value(A, &e,index1, .,indexn) Assign(&A,e,index1, .,indexn),23,数组 char array110=“Hello”; char array210=H,e,l,l,0; char array310=“Hello”; int a15=1,2,3,4,5; int a2=1,2,3,4
11、,5;,24,5.2 数组的顺序表示和实现,数据一般不进行插入和删除操作。所以,采用顺序存储表示较合适。 数组是多维的结构,而存储空间是一个一维的结构。 在选择存储结构的时候,要对维度进行排列,也就是先按照哪个维度的下标进行元素的存放。,例如,二维数组有两种存储方式: 1)以列序为主序的存储方式; FORTRAN采用列优先; 2)以行序为主序的存储方式。 C和PASCAL中一般采用行优先顺序。,25,例如:,称为基地址或基址。,以“行序为主序”的存储映象,二维数组Amn中任一元素ai,j 的存储位置LOC(i,j) = LOC(0,0) + (inj),a0,1,a0,0,a0,2,a1,0,
12、a1,1,a1,2,a0,1,a0,0,a0,2,a1,0,a1,1,a1,2,L,L,26,例如:,称为基地址或基址。,以“列序为主序”的存储映象,二维数组Amn中任一元素ai,j 的存储位置LOC(i,j) = LOC(0,0) + (jmi),a0,1,a0,0,a0,2,a1,0,a1,1,a1,2,a1,0,a0,0,a0,1,a1,1,a0,2,a1,2,L,L,27,例1:一个二维数组A,行下标的范围是1到6,列下标的范围是0到7,每个数组元素用相邻的6个字节存储,存储器按字节编址。那么,这个数组的体积是 个字节。,288,答: Volume=m*n*L=(6-1+1)*(7-
13、0 +1)*6=48*6=288,28,5.3 矩阵的压缩存储(自学),讨论: 1. 什么是压缩存储? 若多个数据元素的值都相同,则只分配一个元素值的存储空间,且零元素不占存储空间。 2. 所有二维数组(矩阵)都能压缩吗? 未必,要看矩阵是否具备压缩条件。 3. 什么样的矩阵具备压缩条件? 一些特殊矩阵,如:对称矩阵,对角矩阵,三角矩阵,稀疏矩阵等。,29,数组和广义表的特点:一种特殊的线性表 所有数据元素仍属同一数据类型。 元素的值并非原子类型,可以再分解,表中元素也是一个线性表(即广义的线性表)。,30,5.4 广义表的定义,一、广义表的抽象数据类型定义: ADT GList 数据对象:D
14、ei | i=1,2,n; n0; eiAtomSet 或 eiGList,AtomSet为某个数据对象 数据关系:LR| ei-1 ,eiD, 2in ADT GList,基本操作:,31, 结构的创建和销毁InitGList(,基本操作, 状态函数GListLength(L); GListDepth(L);GListEmpty(L); GetHead(L); GetTail(L);, 插入和删除操作InsertFirst_GL(, 遍历Traverse_GL(L, Visit();,32,二、基本概念 1.定义:广义表是递归定义的线性结构,是线性表的推广,也称为列表(Lists)记为: L
15、S = ( 1, 2, , n ),广义表名 表头 表尾 (Head) (Tail),n是表长,33,用小写字母表示原子类型,用大写字母表示列表。 第一个元素是表头,而其余元素组成的表称为表尾。,在广义表中约定:,讨论:广义表与线性表的区别和联系? 广义表中元素既可以是原子类型,也可以是列表; 当每个元素都为原子且类型相同时,就是线性表。,34,广义表是一个多层次的线性结构,例如:,D=(E, F),其中:E=(a, (b, c)F=(d, (e),D,E,F,a,( ),d,( ),b,c,e,D=(a,(b,c), (d,(e),35,2.广义表 LS =(1,2,n )的结构特点:,1)
16、广义表中的数据元素有相对次序; 2)广义表的长度定义为最外层包含元素个数; 3)广义表的深度定义为所含括弧的最大重数;注意:“原子”的深度为0;“空表”的深度为 1 4)广义表可以共享; 5)广义表可以是一个递归的表; 递归表的深度是无穷值,长度是有限值。 6) 任何一个非空广义表LS = ( 1, 2, , n)均可分解为表头Head(LS) = 1和表尾Tail(LS) = ( 2, , n) 两部分。,特别提示:任何一个非空表,表头可能是原子,也可能是列表;但表尾一定是列表。,36,E=(a,E)=(a,(a,E)= (a,(a,(a,.),E为递归表,1)A =( ) 2)B = (
17、e ) 3)C =( a ,( b , c , d ) ) 4)D=( A , B ,C ) 5)E=(a, E),例1:求下列广义表的长度。,n=0,因为A是空表 n=1,表中元素e是原子 n=2,a 为原子,(b,c,d)为子表 n=3,3个元素都是子表 n=2,a 为原子,E为子表,D=(A,B,C)=( ),(e),(a,(b,c,d),共享表,长度定义为最外层包含元素个数;,37,例2: D = ( E, F ) = (a, (b, c),F ),Head( D ) = Tail( D ) =,Head( E ) = Tail( E ) =,Head( ( b, c) ) = Tai
18、l( ( b, c) ) =,Head( ( b, c) ) = Tail( ( b, c) ) =,Head( ( c ) ) = Tail( ( c ) ) =,E,( F ),a,( ( b, c) ),(b, c),( ),b,c,( ),(c),38,1. GetTail (b, k, p, h) ; 2. GetHead (a,b), (c,d) ; 3. GetTail (a,b), (c,d) ; 4. GetTail(GetHead(a,b),(c,d) ;,例3:求下列广义表操作的结果,(k, p, h),(b),5. GetTail((e)) ; 6. GetHead( ( ( ) ) . 7. GetTail( ( ( ) ) ) .,( ),(a,b),( ),( ),(c,d),39,5.4 广义表的存储结构(自学),由于广义表的元素可以是不同结构(原子或列表),难以用顺序存储结构表示 ,通常用链式结构,每个元素用一个结点表示。,注意:列表的“元素”还可以是列表,所以结点可能有两种形式,表结点: 原子结点:,