优秀课件笔记之串

第四章 串
 4.1 串类型的定义
 4.2 串的表示和实现
4.2.1 定长顺序存储表示
4.2.2 堆分配存储表示
4.2.3 串的块链存储表示
 4.3 串的模式匹配算法
一、串及其基本概念
串的定义:串(String)是零个或多个字符组成的有限序列。
一般记作S=“
a1a2a3…
an”
,其中S是串名,双引号括起来的字符
序列是串值;ai(1≦i≦n)可以是字母、数字或其它字符。
串的长度:串中所包含的字符个数称为该串的长度。
空串:长度为零的串称为空串(Empty String) ,它不包含任何
字符。
空格串:将仅由一个或多个空格组成的串称为空格串(Blank
String)。注意:空串和空格串的不同,例如“

和“”
分别表
示长度为1的空格串和长度为0的空串。
4.1 串类型的定义
子串与主串:串中任意个连续字符组成的子序列称为该串的子
串,包含子串的串相应地称为主串。通常将子串在主串中首
次出现时的该子串的首字符对应的主串中的序号,定义为子
串在主串中的位置。
例如,设A=“
This is a string ”
B=“
is”
则B是A的子串,A
为主串。B在A中出现了两次,其中首次出现所对应的主串位
置是3。因此,称B在A中的位置为3。
相等:当且仅当两个串的长度相等,并且每个对应位置的字符
都相等时,称两个串相等。
例如,A=“
BEIJING”
B=“
BEIJING”
,则串A与串B相等。
串常量和串变量:串常量和整常数、实常数一样,在程序中只
能被引用但不能改变其值,即只能读不能写。串变量的值在
程序中可以改变,即可以读也可以写。
4.1 串类型的定义
二、串的抽象数据定义
串的抽象数据类型定义见教材P71
三、串的基本操作
对于串的基本操作,许多高级语言均提供了相应的运算或
标准库函数来实现。下面仅介绍几种在C语言中常用的串运算。
定义下列几个变量:
char s1[20]= “
dirtreeformat ”
,
s2[20]=“
file.txt ”
;
char s3[30], *p;
int result;
4.1 串类型的定义
1 求串长(length)
int strlen(char *s); //求串的长度
例如:printf(“
%d”
,strlen(s1)); 输出13
2 串复制(copy)
char *strcpy(char *to,char *from);
该函数将串from复制到串to中,并且返回一个指向串to的开
始处的指针。
例如:strcpy(s3,s1); //s3= “
dirtreeformat ”
3 联接(concatenation)
char strcat(char *to,char *from)
该函数将串from复制到串to的末尾,并且返回一个指向串to
的开始处的指针。
例如:strcat(s3 , “
/”
)
strcat(s3,s2); //s3= “
dirtreeformat/file.txt ”
4.1 串类型的定义
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(“
Jos”
,“
Joseph”
); //result<0
5 字符定位(index)
char strchr(char *s,char c);
该函数是找c在字符串中第一次出现的位置,若找到则返回该
位置,否则返回NULL。
例如:p=strchr(s2, “
.”
); //p指向“
file”
之后的位置
if(p) strcpy(p, “
.cpp”
); //s2= “
file.cpp ”
4.1 串类型的定义
2
Page 2
例1、求子串
求子串的过程即为复制字符序列的过程,将串S中的第pos个
字符开始长度为len的字符复制到串T中。
void substr(char *sub,char *s,int pos,int len)
{ if( pos<0 || pos>strlen(s)-1 || len<0 )
error( “
parameter error ”
);
strncpy(sub,s+pos,len );
}
例2、串的定位index(char *s,char *t,int pos)
求串T在主串S中第pos个字符之后的位置。方法:从主串S的第
pos个字符开始,取长度和串T相等的子串和T比较,若相等,则求
得函数值为pos。否则子串位置增1继续与T比较,直至找到与T相
等的子串或确定S中不存在和串T相等的子串为止。
4.1 串类型的定义
int index(char *s, char *t, int pos)
{ if( pos>0 )
{ n = strlen( s );
m = strlen( t );
i = pos;
while( i<n-m+1 )
{ substr( sub, s, i, m );
if( strcmp( sub, t ) != 0 )
++i;
else return( i );
}
}
return( 0 );
}
4.1 串类型的定义
定长顺序存储表示,也称为静态存储分配的顺应表。它是用一组
连续的存储单元来存放串中的字符序列。所谓定长顺序存储结构,
是直接使用定长的字符数组来定义,数组的上界预先给出:
#define maxstrlen 255
typedef char SString[maxstrlen ]; // 0分量存放串长
4.2 串的表现和实现
4.2.1 定长顺序存储表示
Status SubString( SString &Sub, SString S, int pos, int len )
{ if( pos < 1 || pos > S[0] || len < 0 || len > S[0]-pos+1 )
return ERROR;
Sub[1..len] = S[pos..pos+len-1];
Sub[0] = len;
retrun OK;
}
Status Concat(SString &T, SString S1, Sstring S2)
{ if( S1[0] + S2[0] <= maxstrlen )
{ T[1..S1[0]] = S1[1..S1[0]];
T[S1[0]+1..S1[0]+S2[0]] = S2[1..S2[0]];
T[0] = S1[0] + S2[0]; return TRUE;
}
else if ( S1[0] < maxstrlen )
{ T[1..S1[0]] = S1[1..S1[0]];
T[S1[0]+1..maxstrlen] = S2[1..maxstrlen-S1[0]];
T[0] = maxstrlen; return FALSE;
}
else
{ T[0..maxstrlen] = S1[0..maxstrlen];
return FALSE;
}
}
4.2 串的表现和实现
以一组地址连续的存储单元存放串值字符序列,但它们的存
储空间是在程序执行过程中动态分配而得,所以也称为动态存储
分配的顺序表。在C语言中,利用和等动态存储管理函数,来根据
实际需要动态分配和释放字符数组空间。
typedef struct{
char *ch;
int length;
} HString;
4.2.2 堆分配存储表示
4.2 串的表现和实现
Status strassign(HString t, char *chars){
//生成一个其值等于串常量chars的串t
if(t.ch) free(t.ch);
for(i=0, c=chars; c; ++i, ++c) ; // 求chars的长度
if(!i) { t.ch=NULL; t.length=0; }
else
{ if(!(t.ch=(char *)malloc(i*sizeof(char))))
exit(overflow);
t.ch[0..i-1] = chars[0..i-1];
t.length=i;
}
}
4.2 串的表现和实现
3
Page 3
int strlen(HString s){ return s.length; }
Status clearstring(HString s)
{ if(s.ch) { free(s.ch); s.ch=NULL;}
s.length=0;
}
int strcmp(HString s, HString t)
{ for(i=0; 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;
}
4.2 串的表现和实现
Status concat(HString t, HString s1, HString s2)
{ if(t.ch) free(t.ch);
if(!(t.ch=(char*)malloc((s1.length+s2.length)*sizeof(char))))
exit(overflow);
t.ch[0..s1.length-1]=s1.ch[0..s1.length-1];
t.length=s1.length+s2.length;
t.ch[s1.length..t.length-1]=s2.ch[0..s2.length-1];
return OK;
}
4.2 串的表现和实现
Status substr(HString sub, HString s, int pos, int 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-1..pos+len-2];
s.length= len;
}
return OK;
}
4.2 串的表现和实现
顺序串上的插入和删除操作不方便,需要移动大量的字
符。因此,可用单链表方式来存储串值,串的这种链式存储
结构简称为链串。
一个链串由头指针唯一确定。这种结构便于进行插入和
删除运算,但存储空间利用率太低。
A B C D E F G H I # # # ^
head
head
A B C I ^
4.2.3 串的块链存储表示
4.2 串的表现和实现
4.3 串的模式匹配算法
……
S
i-j+1
S
i-j+2
……
S
i-1
S
i
S
i+1
……
P
1
P
2
……
P
j-1
P
j
……

失配位置
P
1
P
2
……
P
j-1
P
j
……
下次匹配位置
e.g: S=a b c a b c a b c d
P= a b c a b c d
a b c a b c d
模式右移一位
4.3.1 求子串位置的定位函数Index( )
模式匹配:求子串(模式)在主串的位置。
基本方法:从指定位置开始逐个比较主串与模式的字符,一旦
发现出现字符不匹配,则整个模式相对于原来的位
置右移一位。如下图所示:
最基本的模式匹配程序:
int Index( SString S, SString T, int pos )
// 在主串S的第POS个字符之后,寻找模式T的匹配位置
{ i = pos ; j = 1;
while ( i <= S[0] && j <= T[0] ) // 0 号单元存放串长
{ if ( S[i] == T[j] ) { ++i ; ++j ; }
else { i = i - j + 2; j = 1; }
}
if ( j > T[0] ) return i-T[0] // T 在S中的匹配起始位置
else return 0;
}
4.3 串的模式匹配算法
演示
4
Page 4
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
S=
aaaaaaaaab
P=
aab
S=
aaaaaaaaab
P=
aab
S=
aaaaaaaaab
P=
aab
S=
aaaaaaaaab
P=
aab
a
、b
不等
模式右移一位
a
、b
不等
模式右移一位
a
、b
不等
模式右移一位
完全匹配
n-m+1
匹配起始位置
4.3 串的模式匹配算法
4.3.2 Knuth-Morris-Pratt
模式匹配算法(KMP
算法)
说明基本模式匹配算法在最坏情况下时间复杂度为
O

n
*
m
)的实
例(n
为主串长度,m
为模式长度)。每比较m
次,移动模式一次。最后
在主串的
n-m+1
找到主串,比较
(n-m+1
)*
m


S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
失配点
右移一位,仍失配又右移一位,仍失配
再右移一位,三次
比较之后,再进行
断点处的比较,比
较成功!
问题:
能否省去上述五次比
较,直接进行
S7

P4

间的比较呢?
本次比较省去? 本次比较省去?
三次比较省去?
4.3 串的模式匹配算法
说明
KMP
算法的实例:
i
j
S =
abcabcabcd
P =
abcabcd
S =
abcabcabcd
P =
abcabcd
失配点
直接寻找新匹配位置
i
j

S
i-j+1
S
i-j+2
……
S
i-1
S
i
S
i+1
……
P
1
P
2
……
P
j-1
P
j
……

失配点

分析:当
S
i

P
j
发生失配时,
S
i-j+1
S
i-j+2
……
S
i-1

P
1
P
2
……
P
j-1

S
i-k
S
i-k+1
……
S
i-1
S
i
S
i+1
……
P
1
……
P
k-1
P
k
……

失配点
如果:
P
1
P
2
………
P
k-1
= P
j-k+1
P
j-k+2
………
P
j-1

可以直接比较S
i

P
k
4.3 串的模式匹配算法
int
Index_KMP( SString S, SString T, int
pos )
// 在主串S的第POS个字符之后,寻找模式T的匹配位置
// 已知 NEXT 函数值,T 非空,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] // T在S中的匹配起始位置
else return
0;
} // Index_KMP
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值