(al初始化
temp叫 硎
( b ) s t r n c p y ( t e m p , s , i ) f t t f f Z f ,
temp
( c ) s t r c a t ( t e m p , tl l\ttjZ)G
teIn
(d) strcat(temp` s+土 ) 书 戈 彳∫歹L丿 斤
图 2,10字 符 中插 入举例
稆序 2.12把 一个字符 串插 入 另一个,通 常的 str⊥ng.h中 无此函数。冈为两个串都有可 能是空 串,程 序考虑 了这种情况 。注意 ,str土 ngs(s`匕 `0)与 strcat(t`s)功 能等价 。程序 2.12仅 是标准 串函数 的用法举例 ,读 者在实际 l∶作中不应该用这个函数 ,它 的时间需求和空
间需求都不 讲究 ,temp实 际不需耍 ,改 动稆序可 以去掉这个变 鞋。 □
§2.7.3 模 式 匹配
本小 i∷要讨论一个非常精妙的字符 串算法 。给定两个 串 pa匕、string,要 在 str土ng中 杏找模式 串 pat,最 简单的方法是调用 内部函数 strstr。 给定 以 卜语句 :
char pat[MAX_SIZE]` str土 ng[MAX~SIZE]` ★ t`
71
a u t o \0
72 第 2章 数组和结构
v o i d s t r i n g s ( c h a r * s , c h a r * t , i n t i )
I / . , . i n a a r t - n f r i n r t f i n f o a i n i r t - ^ . S i t i O n i * t
\ / * L I l S e I L b L L L t t g L L l t u v D L L L J T V D a L P v
c h a r s t r i n g I M A X S I Z E ] , * t e m p = s t r i n g ;
i f ( i < 0 & & i > s t r l e n ( s ) ) {
f n r ; n f f ( q i r T a r r n p n q i f . i o n i s o r t f o f h n r r n d q \ n r r ) :
! } / ! I I r U ! \ o u q u ! ! , u f V I l u I D u V U U u v ! u v v s r r s ' u \ r r I I
C X i t ( E X I T _ F A I L U R E ) ; i
)
i f ( ! s t r l e n ( s ) ) s t r c p y ( s , t ) ; e l s e i f ( s t r l e n ( t ) ) i
s t r n c p y ( t e m p , s , a ) ; s t r c a t ( t e m p , t ) ; s t r c a t ( t e m p , ( s + i ) ) ; s t r c p y ( s , t e m p ) ; Il
])
程序 2,12字 符 串插入 函数
卜面一段程序在 串 string中 杏找 串 pat:
土 £ (t=strstr(str主 ng` pat))
pr土 ntf("The凵 str土 ng凵 fr0m凵 strstr凵 ⊥ S:凵 %s\n"` t)`
e1臼 e
pr土 ntf("The凵 pattern凵 was凵 not凵 f° und凵 w土 th凵 Strstr\n")'
如 呆 pat不 在 str土 ng屮 ,(t=strstr(str土 ng`pat))返 Fl空 指 针 。 如 呆 pat|ll现 在 string
中,t指 向 str土ng中 的 pat,然 后打 印 t指 向子串的全部 内容。
尽管 strstr看 起来完全实现 了所需功能,我 们还是决定编写 臼己的模式匹配 函数 ,尝 试各种实现方法 。最简单的一种 ,是 顺序 比较模式 串的每个 字符和主 串的每个字符 ,直 到发 现匹配结束,或 扫描到主 串结束仍 未找到而结束。这种方法虽然简单 ,却 是效率最低 的方法 , 我们把这种方法放到 习题 中讨论 。令 pat的 长度 是 彳,str土 凹 的长度 是 昭,如 果 pat不 出 现在 st土ng中 ,这 种方法 的计算 时间足 O(″ ・彳)。这个结呆并不令人满意 ,以 下方法要好一 此
上述模式匹配 的策略足穷举搜索 ,在 此基础 上,如 果发现 str1en(pat)人 ]=主 串剩 卜的 串长就结束查找 ,可 以减少计算 时问。另外 ,如 呆 pat的 第一个字符和 st ont匹 配 ,马 上 拿 pat的 最后一个字符和 str土ng的 对应位置 比较 ,能 进一步捉高效率 。程序 2.13的 nf土nd 是这两种改进 的实现 。
例 2.3m血 d运 行 实 例 )假 定 pat="aab"、 str土 ng="ababbaabaa",图 2.11是 nf主 nd比 较
pat与 str土 ng的 运 行 过 程 。 1asts、 1astp分 别 str土 ng、 pat的 尾 指 针 。 首 先 ,nf土 nd比
较 str土 ng[endmatch]不 冂 pat[1astp],如 j呆 相 耸 ,nf土 nd移 动 土 、 j继 续 比 较 ,直 到 失 配 或
完 全 匹 配 ,如 呆 发 生 失 配 start用 来 重 置 土 。 □
§2.7字 符串 73
i n t n f i n d ( c h a r * s t r i n g , c h a r * P a t )
| / - n = r n h r h e l _ a s t c h a r a c t e r o f p a t t e r n f i r s t , a n d t h e n m a t c h f r o m
\ / * I l l a e g J t L . l r E
t h e b e g i n n i n g . * / i n t L , j , s t a r t = O ;
i n t l a s t s = s t r l e n ( s t r i n g ) - 1 ; i n t l a s t p = s l r l e n ( P a t ) - 1 ; i n t e n d m a t c h = 1 a s t P ;
f o r ( i = O ; e n d m a t c h < = l a s t s ; e n d m a t c h + + , s t a r t + + ) { i f ( s t r i n g [ e n d m a t c h ] = = p a t I l a s t p ] )
f o r ( j = 0 , i = s L a r t ;
j < l a s t p & & s t r i n g ; i l = = P a t [ j J ; 1 + + , j + + )
t
i f ( j = = l a s t p ) r e t u r n s t a r t ; / * s u c c e s s f u f * /
])
r e t u r n - 1 ;
程序 2.13先 比较模 式 串末尾字符的模 式 匹配
町 彳歹分析 以 str⊥ng="aa.… a"、 pat="a.… ab"为 例,n£ 土nd的 计算时间是 o(昭 ),昭 是 str1ng的 长度,这 个复杂度足线性的,显 然远远优 J=顺i伶 找方法。虽然该方法足顺序杏找 方法的改进,它 的最并情形复杂度依然楚糟糕的 O(冫9御)。 □
我们 的理想是构造最优算法 ,使 时问复杂度达到 O(str1en(str主 ng)+str△ en(pat))。
这个复杂度之所 以最优 ,是 冈为模式Vε配算法在最 厍怙 形,必 须扫描主串!J模式 中的所有字 符至少一次。在扫描过稆 ,如 呆失配 ,我 们不想Fl头 再 么比较主 串中已比较过 的字符 ,而 是 希望利用模式 串的字符信息,以 及模式 申的失配位苴 ,确 定 卜一步应 比较 的主 串和模式串位 置 。这正是 Knuth'Morris'Pra仗 的模式V刂配算法思路 。这个算法 的计算 时间楚线性 的。以 下给 出一个例子 ,假 定
P='伢 抄 c伢 抄 c伢 c伢 乡
′
令 S=sOs1… ・s解-1是 主 串,要 确定 P足 否在 sf开 始处匹配 。如呆 sj≠ 伢则接 卜来显然耍用
s丿 +1和 伢 比 较 。 同 理 ,若 sJ=伢 且 s`+1≠ b,则 接 卜 来 耍 用 sj+1和 l伢 比 较 。 若 s阝 丿+1=劢 且
s`妮 ≠c,则 有 以 P清 形:
S P
?表 示我们不关心 S在 该位置的值 。第一个 ?表 示 s∴+2且 sj+2≠ c。这时,我 们知道,下 一次 应该用 P的 第一个字符直接与 s氵ψ 比较,而 不是 l-J sj+1比较,冈 为我们 己经知道,助+1与 P 的第工个字符 抄相等 ,所 以一定有 sf+1≠ 伢。继续比较 卜去,假 定 P的 前四个字符和 S匹 配,
74 第 2章 数组和结构
lastp (⑴ 模J1串
(⑶ 失 四d
start endmatch (θ失 配
lasts
b a b b
a|a|b
astort endmatch lasts
(g) Lζ酉J
图 2.11n丘 nd仿 页
但 卜一个字符失配 ,即 s`冫 ≠b,这 时的情形是:
仔细观察后 ,我 们发现接 卜来应该用 ss艹 与 P的 第工 个字符 乙相 比,好 像把棋式 串 P 向右滑动 ,使 它 的子 串对准 S的 一个子 串,然 后 让两 个相等 丫串后面 的第一 个字符相 比。通 过观察 ,我 们得 出结论 ,根 据模式 申中的字符信息 ,根 据模式 串失配主 串的字 符位置 ,可 以 确定接下来应该用模式 串的哪个 字符和主 串的当前 失配 宁符继续 比较 ,而 无需冂 去比较主
串的较前位置字符。为确定这个模式 串位置 ,需 要定 义以 卜失配函数 (failure hnction):
_ _
〓 S Ρ
rb)失 配
(dl失 配
endmatch
(el失 配
§2.7字 符串
#def⊥ ne MAX pATTERN sIzE △ 00 土n△ match()氵
vo土 d fa± 1()`
土nt £ a± 1ure[MAX PATTERN SIZE]`
char string[MAX_pATTERN_sIZE]`
76
re△urn ((j==1enp) ? (i-1enp) : 这条语句检 查是否找到模式 串,如 呆未找到 ,那 么模式 串 卜标
§2.8参 考文献和选读材料
把以上分析综合起来,计 算失配函数和uu配 算法的总体时问足
77
O ( s t r l e n ( p a t ) * s t r l e n ( s t r i n g ) ) .
习 题
1,编 写函数,读 入一个字符 申,统 计字符串中不同字符的出现频率。挑选不 同的数据集测 试这个函数 。
2.编 写 函 数 strnde1,参 址 楚
一
个 字 符 串 s乜 r土 ng和 两 个 整 数 start、 1ength。 在 str⊥ ng
中 册 刂|徐 start/1・ 女f)的 1ength个 字 ↑讠
:,鼓
后 返 丨丨丨l string。
3.编 写 函 数 strde1,参 甘 足 字 符 串 string和
′
冫 符 character。 删 除 string屮 第
一
次 出
现 的 character,鼓 后 返 冂 str⊥ nq。
4,编 t了 函 数 strp。 s△ ,参 鞋 足 字 符 串 str土 ng和 宁 符 charac匕 er。 函 数 返 冂
一
个 整 数 ,即 在
str土 ng中 第
一
次 出 现 character的 位 置 。 如 太 character不 在 str土 ng中 ,返 冂 -1。
不
应 调川 str土ng.hL⒈ JF向s匕rp。 函数,虽 然它 不楚 A∶NSI C的 标准 函数,可 楚仃些 C讠手丨l`^
库捉供这 个函数。
5.编 tJ函 数 strchr△ ,完 成 Ij上 题 strp○ △丬‖{1的 功 能 ,不 过返 「Π值 足指 向 string屮
character第 一
次 出 现 的 字 符 指 针 。 劫 l宋 character不 在 str土 ng屮 ,返 Fl NuLL。
6.修 改稆序 2.12,不 川临时变 鞋 temp。 分析新稆序时间复杂度并与原不V序 相 比。
7.证 明 n£土nd的 计算时间足 O(彳彳),″ 足主中 κ度,昭 足模式 串 K度 。川具体的主申、模 式 中加 以说 明。
8,计 算 卜列模式 申的失配函数 :
(a) rInrI砑 乙
(b) 日乙伢抄日伢
(C) 伢 D日 伢乙砑砑抄