字符串匹配算法:穷举、KMP、BM
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
模式匹配是串的基本运算之一. 模式匹配是串的基本运算之一. 有两个字符串T S,字符串 称为正文, 字符串T 有两个字符串T和S,字符串T称为正文, 字符串S称为模式,要求找出模式S 字符串S称为模式,要求找出模式S在正文 中的首次出现的位置.一旦模式S T中的首次出现的位置.一旦模式S在正文 中找到,就说发生一次匹配. T中找到,就说发生一次匹配.有些应用 可能会要求找出所有的匹配位置. 可能会要求找出所有的匹配位置.
设模式S= 设模式S= s0s1…sm-1,则它各字符的失败链接值 next[j]的定义如下 next[j]的定义如下: 的定义如下: k,当0 s k < j,且使得s0s1…sk = j,且使得s
sj-ksj-k+1…sj 的最大整数
next[j] = -1,其它情况 的前缀子串, 称s0s1…sk为s0s1…sj-1sj的前缀子串,sj-ksj-k+1…sj 的后缀子串. 为s0s1…sj-1sj的后缀子串. 设模式S "xyxxyzxz", 设模式S = "xyxxyzxz",按上述公式求得各字符 的失败链接值如表7.1所示 所示. 的失败链接值如表7.1所示.
p0 p1 p2 …pj-1 …pm-1 = ts+1 ts+2 ts+3 … ts+j … ts+m
(1)
如果
p0 p1 …pj-1 ≠ p1 p2 …pj p0 p1 …pj-1 ≠ ts+1 ts+2 … ts+j
(2)
则立刻可以断定 下一趟必不匹配
同样,若 p0 p1 …pj-2 ≠ p2 p3 …pj 同样, 则再下一趟也不匹配, 则再下一趟也不匹配,因为有
T t0 … ts-1 ts ts+1 ts+2 … ts+j-1 ts+j ts+j+1 … tn-1 ‖ ‖ ‖ ‖ ‖ × P p0 p1 p2 … pj-1 pj pj+1 则有 ts ts+1 ts+2 … ts+j = p0 p1 p2 …pj 为使模式 P 与目标 T 匹配,必须满足 匹配,
在计算机非数值计算应用中, 在计算机非数值计算应用中,经常遇到字符序列的处 文字编辑,情报检索,自然语言翻译, 理.如,文字编辑,情报检索,自然语言翻译,事务 处理,图象处理等应用中经常遇到的那样. 处理,图象处理等应用中经常遇到的那样.在计算机 一个字符集上的每个字符用定长的代码表示, 中,一个字符集上的每个字符用定长的代码表示,所 有可能的各种字符都可以对应一个确定的代码. 有可能的各种字符都可以对应一个确定的代码.一个 特定的字符序列称为字符串,简称为串. 特定的字符序列称为字符串,简称为串.有两种方法 能比较方便地表示一个字符串. 能比较方便地表示一个字符串.一是人为地约定一个 特殊的代码为字符序列的结束符, 特殊的代码为字符序列的结束符,每个字符串最后都 有这个结束符.二是, 有这个结束符.二是,为每个字符序列另引入一个整 让该整数指出该字符串的字符个数. 数,让该整数指出该字符串的字符个数.本书采用第 一种表示字符串的方法
简单模式匹配的缺点: 简单模式匹配的缺点: 无谓比较
S T U D E N S T U D E N T…… ‖‖ ‖‖ ‖ ‖ × 模式 pat S T U D E N T 目标 T S T U D E N S T pat S T U D E N T …… S T U D E N S T U D E N T…… 目标 T ‖‖ ‖‖ ‖ ‖ ‖ S T U D E N T 模式 pat
表7.1 字符失败链接值
J 0 1 2 3 4 5 6 7 S x y x x y Z x z next[j] -1 -1 0 0 1 -1 0 -1
j = 0时,没有满足0sk<j的k存在,next[0]=-1. 0时 没有满足0sk<j的 存在,next[0]=j = 1时,可取k=0,但s0≠s1,k不符合要求, 1时 可取k=0, s0≠s1, 不符合要求, next[1]=next[1]=-1. j = 2时,k可能取0或1,s0=s2,且s0s1≠s1s2, 2时 可能取0 s0=s2, s0s1≠s1s2, 所以,k=0,next[2]=0. 所以,k=0,next[2]=0. j = 3时,k可能取0,1或2,s0=s3,且 3时 可能取0 s0=s3, s0s1≠s2s3,s0s1s2≠s1s2s3,所以取k=0, s0s1≠s2s3,s0s1s2≠s1s2s3,所以取k=0, next[3]=0. next[3]=0. j = 4时,k可能取0,1 ,2或3,s0≠s4,且 4时 可能取0 s0≠s4, s0s1=s3s4,s0s1s2≠s2s3s4, s0s1=s3s4,s0s1s2≠s2s3s4,s0s1s2s3≠s1s2s3s4 所以取k=1,next[4]=1.其余类推. ,所以取k=1,next[4]=1.其余类推.
因此,当正文T在t[j+i]比较失败时,正文t的扫 比较失败时, 因此,当正文T t[j+i]比较失败时 正文t 视指针j不回溯, 视指针j不回溯,仍指向上一趟匹配失败的字符 即从此处开始继续比较,而模式s扫视指针i ,即从此处开始继续比较,而模式s扫视指针i 回退到k 即模式从s[k]开始 开始, 回退到k,即模式从s[k]开始,这就省去了前面 次比较.如果对应s[i]的 有多个, 的k次比较.如果对应s[i]的k有多个,应取最 大的k 大的k. 这样,在匹配比较过程中,一旦出现s[i] 这样,在匹配比较过程中,一旦出现s[i] ≠ t[j+i]时 就要找出s[i]对应的 t[j+i]时,就要找出s[i]对应的k,称k为s[i]的失 对应的k s[i]的失 败链接值.寻找s的各字符的失败链接值, 败链接值.寻找s的各字符的失败链接值,只 与模式S本身有关,与正文T无关. 与模式S本身有关,与正文T无关.
字符串 (String) String)
字符串是n 字符串是n ( ≥ 0 ) 个字符的有限序列,记 个字符的有限序列, 作 S : "c0c1c2…cn-1" 其中, 其中,S是串名字 "c0c1c2…cn-1"是串值 ci是串中字符 n是串的长度. 是串的长度. 如:"Welcome to Shanghai !!!"
p0 p1 …pj-2 ≠ ts+2 ts+3 … ts+j
直到对于某一个" " 直到对于某一个"k"值,使得 且 则
p0 p1 …pk+1 ≠ pj-k-1 pj-k …pj p0 p1 …pk = pj-k pj-k+1 …pj p0 p1 …pk = ts+j-k ts+j-k+1 … ts+j ‖ ‖ ‖ pj-k pj-k+1 … pj
若不考虑正文至少有模式长的字串个数,且用 若不考虑正文至少有模式长的字串个数, 字符指针编写,可简写成以下形式. 字符指针编写,可简写成以下形式. char *stringSearch(char *t, char *s) { char *q, *p; for(; *t != '\0'; t++) '\ for(q = t, p = s; *p != '\0' && *q == *p; '\ q++, p++) { } return *p == '\0' ? t : NULL; '\ }
×
直接跳过子串可能错过成功比较
F I F I F I Y U D E N T…… ‖‖ ‖‖ × 模式 pat F I F I Y 目标 T F I F I F I Y U D E N T…… ‖‖ × F I F I Y 模式 pat
直接跳过错过成功比较
目标 T
目标 T
F I F I F I Y U D E N T…… ‖‖ ‖‖‖ F I F I Y 模式 pat
穷举的模式匹配算法时间代价: 穷举的模式匹配算法时间代价: 最坏情况比较n +1趟 趟比较m 最坏情况比较n-m+1趟,每趟比较m次, 总比较次数达( m+1)*m 总比较次数达(n-m+1)*m 原因在于每趟重新比较时 每趟重新比较时, 原因在于每趟重新比较时,目标串的检 测指针要回退. 测指针要回退.改进的模式匹配算法可 使目标串的检测指针每趟不回退. 使目标串的检测指针每趟不回退. 改进的模式匹配(KMP)算法的时间代价 算法的时间代价: 改进的模式匹配(KMP)算法的时间代价: 若每趟第一个不匹配,比较n-m+1趟, 若每趟第一个不匹配,比较n +1趟 总比较次数最坏达( )+m 总比较次数最坏达(n-m)+m = n 若每趟第m个不匹配, 若每趟第m个不匹配,总比较次数最坏亦 达到 n
7.1 简单匹配 第 1趟 第 2趟 第 3趟 第 4趟 T P T P T P T P abbaba aba abbaba aba abbaba aba abbaba aba √ 穷举的模式 匹配过程
char *stringSearch(char *t, char *p) { int n = strlen(t), m = strlen(p), i, j; for(j = 0; j <= n - m; j++) { /* 从t[j]开始的子串与字符串 比较 */ 开始的子串与字符串p比较 开始的子串与字符串 for(i = 0; i < m && t[j+i] == p[i]; i++); if (i == m) return t+j; } return NULL; }
求s的各字符的失败链接值算法: 的各字符的失败链接值算法: 引入数组next[] 元素个数为S的长度, next[], 引入数组next[],元素个数为S的长度,依次存 各字符的失败链接值.先置next[0] 放S各字符的失败链接值.先置next[0] = -1, 在已求得next[0] next[0], next[j-1]的情况下 的情况下, 在已求得next[0],…,next[j-1]的情况下, next[j].如next[j-1]=k,又有s[k]=s[j-1], 又有s[k]=s[j 求next[j].如next[j-1]=k,又有s[k]=s[j-1], 那末置next[j] next[jnext[j]为 那末置next[j]为next[j-1]+1; 如果s[k]≠s[j 1], k1=next[k],如有 s[k]≠s[j如果s[k]≠s[j-1],令k1=next[k],如有 s[k1]=s[j-1],则置next[j]为 则置next[j] s[k1]=s[j-1],则置next[j]为k1+1; 如果s[k1]≠s[j 1],则按s[k1]的失败链接值再 如果s[k1]≠s[j-1],则按s[k1]的失败链接值再 s[k1]≠s[j则按s[k1] 继续寻找,直至找到一个失败链接值kn, kn,使得 继续寻找,直至找到一个失败链接值kn,使得 s[kn]=s[j-1],或者kn s[kn]=s[j-1],或者kn = -1,这时就置 kn+1. next[j] = kn+1.
7.2 KMP算法 算法
改进的模式匹配: 改进的模式匹配:
寻找最大"跳跃" 寻找最大"跳跃"
t0 t1 t2 …… tj-1 tj …… tn-1 ‖‖ ‖ ‖X 模式 pat p0 p1 p2 …… pj-1 pj …… pm-1 目标 T 模式 pat t0 t1 … tk … … tn-1 p0 p1 …… pm-2 pm-1 目标 T
串的模式匹配
定义 在串中寻找子串(第一个字 在串中寻找子串( 符)在串中的位置 在模式匹配中,子串称为模 词汇 在模式匹配中,子串称为模 串称为目标 目标. 式,串称为目标. Beijing" 示例 目标 T : "Beijing" jin" 模式 P : "jin" 匹配结果 = 3
记正文T的字符个数为n 记正文T的字符个数为n,令 T= t0t1t2…tn-1, 记模式S的字符个数为m 记模式S的字符个数为m,令 S= s0s1s2…sm-1. 若正文中自位置k开始有一次匹配, 若正文中自位置k开始有一次匹配,则有 sj = tk+j,0 <= j < m. m. 并且对所有p<k,没有对所有的0<=j<m, 并且对所有p<k,没有对所有的0<=j<m,m个等 式 sj = tp+j 全都成立. 全都成立.