一看就懂的字符串匹配算法 之 RK算法
RK算法是对BF算法的进一步优化,很巧妙的使用了哈希算法,让匹配的效率有了很大的提升。
BF算法 这是关于BF暴力匹配算法的博客,大家可以先去看看。
RK算法的原理和实现
之前在讨论BF算法的时候,我们说过关于模式串长度m,和主串长度n,那么在主串中就会有n-m+1个长度为m的子串,我们只需要暴力的一一对比n-m+1个子串与模式串,就可以找出主串中与模式串匹配的子串。
但是这样就会出现一个问题,在每次检查子串和模式串是否匹配的时候,需要依次对比每个字符,比较耗时,所以我们现在就需要稍微进行改造,增加哈希算法,来加快子串与模式串的匹配。
具体的思路是通过哈希算法对主串中的n-m+1个子串分别求哈希值,然后与模式串的哈希值进行比较。如果某个子串的哈希值等于模式串,那就说明子串与模式串相匹配(暂时不讨论哈希冲突的问题)。因为哈希值是一个数字,数字之间比较是否相等是非常快速的,所以模式串和子串的比对的效率就提高了。
这时候大家可能也注意到一个问题了,就是尽管借助了哈希值,模式串与子串比对的效率提高了,不过通过哈希算法计算子串哈希值的过程,需要遍历子串中的每个字符,这个过程就比较耗时。也就是说,整体的效率并没有提高。
那我们如果假设主串和模式串对应的字符集只包含K个字符,我们可以用一个K进制数来表示一个子串,把K进制数转换为十进制数,作为子串的哈希值。现在看看这个例子。
例如:要处理的字符串只包含a到z这26个小写字母,那么我们就用26进制来表示一个子串,我们把a到z这26个字符映射到0到25这26个数字,如下图一样,计算哈希值时,相对于十进制字符串,我们只需要把进位从10改为26.
上面说的哈希算法有一个特点:在主串中,相邻两个子串哈希值的计算公式有一顶的关系。
上图这是十进制字符串和十六进制字符串的哈希值计算。
上图是相邻子串哈希值计算。
通过这个例子,我们可以得出这样的规律:相邻子串s[i-1]和s[i]对应的哈希值计算公式有交集,也就是说,我们可以使用s[i-1]的哈希值快速的计算出s[i]的哈希值。
RK算法的性能分析
RK算法耗时的逻辑主要包含两个部分:计算子串的哈希值和比较模式串与子串的哈希值。对于计算字串的哈希值,我们可以设计特殊的哈希算法,只需要扫描一遍主串就能得到所以子串的哈希值,因此,这一部分的时间复杂度为O(n)。对于比较模式串与子串的哈希值,这部分的时间复杂度也为O(n)。综合起来,RK算法的时间复杂度为O(n)。
这个时候可能还会出现一个问题,图个模式串很长,相对应的主串中的子串也很长,那么通过上面计算出的哈希值可能就会很大,如果哈希值超过了计算机整型类型可以表示的范围,那又应该怎么办呢?
实际上,前面设计的基于二十六进制的哈希算法是没有哈希冲突的,也就是说,一个字符串与一个二十六进制数一一对应,不同的字符串的哈希值肯定不一样,十六进制字符串对应的十进制也是不会有冲突的。不过,对于模式串很长的情况下,为了能将哈希值落在整形数据表示的范围内,存在哈希冲突也是可以接收的,那么此时又该怎么设计哈希算法呢?
基于C语言的代码
//
// main.c
// 003--RK匹配算法
//
// Created by CC老师 on 2019/10/29.
// Copyright © 2019年 CC老师. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//d 表示进制
#define d 26//4.为了杜绝哈希冲突. 当前发现模式串和子串的HashValue 是一样的时候.还是需要二次确认2个字符串是否相等.
int isMatch(char *S, int i, char *P, int m)
{int is, ip;for(is=i, ip=0; is != m && ip != m; is++, ip++)if(S[is] != P[ip])return 0;return 1;
}//3.算出最d进制下的最高位
//d^(m-1)位的值;
int getMaxValue(int m){int h = 1;for(int i = 0;i < m - 1;i++){h = (h*d);}return h;
}/** 字符串匹配的RK算法* Author:Rabin & Karp* 若成功匹配返回主串中的偏移,否则返回-1*/
int RK(char *S, char *P)
{//1. n:主串长度, m:子串长度int m = (int) strlen(P);int n = (int) strlen(S);printf("主串长度为:%d,子串长度为:%d\n",n,m);//A.模式串的哈希值; St.主串分解子串的哈希值;unsigned int A = 0;unsigned int St = 0;//2.求得子串与主串中0~m字符串的哈希值[计算子串与主串0-m的哈希值]//循环[0,m)获取模式串A的HashValue以及主串第一个[0,m)的HashValue//此时主串:"abcaadddabceeffccdd" 它的[0,2)是ab//此时模式串:"cc"//cc = 2 * 26^1 + 2 *26 ^0 = 52+2 = 54;//ab = 0 * 26^1 + 1 *26^0 = 0+1 = 1;for(int i = 0; i != m; i++){//第一次 A = 0*26+2;//第二次 A = 2*26+2;A = (d*A + (P[i] - 'a'));//第一次 st = 0*26+0//第二次 st = 0*26+1St = (d*St + (S[i] - 'a'));}//3. 获取d^m-1值(因为经常要用d^m-1进制值)int hValue = getMaxValue(m);//4.遍历[0,n-m], 判断模式串HashValue A是否和其他子串的HashValue 一致.//不一致则继续求得下一个HashValue//如果一致则进行二次确认判断,2个字符串是否真正相等.反正哈希值冲突导致错误//注意细节://① 在进入循环时,就已经得到子串的哈希值以及主串的[0,m)的哈希值,可以直接进行第一轮比较;//② 哈希值相等后,再次用字符串进行比较.防止哈希值冲突;//③ 如果不相等,利用在循环之前已经计算好的st[0] 来计算后面的st[1];//④ 在对比过程,并不是一次性把所有的主串子串都求解好Hash值. 而是是借助s[i]来求解s[i+1] . 简单说就是一边比较哈希值,一边计算哈希值;for(int i = 0; i <= n-m; i++){if(A == St)if(isMatch(S,i,P,m))return i;St = ((St - hValue*(S[i]-'a'))*d + (S[i+m]-'a'));}return -1;
}int main()
{char *buf="abcaadddabceeffccdd";char *ptrn="cc";printf("主串为%s\n",buf);printf("子串为%s\n",ptrn);int index = RK(buf, ptrn);printf("find index : %d\n",index);return 1;
}
一看就懂的字符串匹配算法 之 RK算法相关推荐
- 一看就懂的字符串匹配算法 之 BM算法
先来一个导读,关于BM算法开始有了难度,大家一定要静下心,咬着呀也得给我读下去,这样你才能有收获. 我们在文本编辑器中,我们经常用到查找及替换功能.比如说,在Word文件中,通过查找及替换功能,可以把 ...
- diff算法阮一峰_【重学数据结构与算法(JS)】字符串匹配算法(三)——BM算法
前言 文章的一开头,还是要强调下字符串匹配的思路 将模式串和主串进行比较 从前往后比较 从后往前比较 2. 匹配时,比较主串和模式串的下一个位置 3. 失配时, 在模式串中寻找一个合适的位置 如果找到 ...
- 大量的数据做字符串匹配_【重学数据结构与算法(JS)】字符串匹配算法(三)——BM算法...
前言 文章的一开头,还是要强调下字符串匹配的思路 将模式串和主串进行比较 从前往后比较 从后往前比较 2. 匹配时,比较主串和模式串的下一个位置 3. 失配时, 在模式串中寻找一个合适的位置 如果找到 ...
- 字符串匹配算法之BM算法
BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...
- 字符串匹配算法:Horspool算法
Horspool 字符串匹配算法对Boyer-Moore算法的简化算法. Horspool 算法是一种基于后缀匹配的方法,是一种"跳跃式"匹配算法,具有sub-linear亚线性时 ...
- 字符串匹配算法:Sunday算法
背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是\(Ω(m*n)\),也就是达到了字符串匹配效率的下限.于是后来人经过研究,构造出了著名的KMP算法 ...
- 字符串处理 —— 单模式匹配 —— 朴素的字符串匹配算法(BF 算法)
[算法流程] 朴素的字符串匹配算法即暴力匹配算法(BF,Brute Force),其本质是暴力枚举,主要特点有: 没有预处理阶段: 滑动窗口总是后移 1 位: 对模式中的字符的比较顺序不限定,可以从前 ...
- 字符串匹配算法之Sunday算法
字符串匹配查找算法中,最着名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore).两个算法在最坏情况下均具有线性的查找时间.但是在实用上,KMP算法并不比最简 ...
- 字符串匹配算法(BF算法KMP算法)
字符串匹配算法 暴力匹配(BF)算法 KMP算法 next数组 求next数组的练习 next数组的优化(nextval数组) 练习 暴力匹配(BF)算法 BF算法,即暴力(Brute Force)算 ...
最新文章
- 【开源方案共享】VDO-SLAM:基于视觉的动态SLAM感知系统
- 伪共享(false sharing),并发编程无声的性能杀手
- DL之ResNet:ResNet算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
- 学习笔记27—python中numpy.ravel() 和 flatten()函数
- 在ie8下ext显示的问题
- 注解@Component方式代替xml装配bean
- r语言系统计算上是奇异的_R语言实现并行计算
- 【数据结构学习之完全从零实现所有数据结构的代码编写之二】智能指针
- mysql 撤销删除_线上磁盘告警,mysql无法释放空间,踩了个大坑,大家记得别踩坑...
- springboot整合netty
- VB利用SHFileOperation实现拷贝、删除、重命名文件
- 常见的十二种逻辑谬误
- 计算机专业英语四六级,英语四级历年真题,历年四六级真题电子版?
- token与refresh token
- 年利率、七日年化收益率、万份收益
- MSP430初学:MSP430单片机C语言基础(二)
- JAVA计算机毕业设计网课系统(附源码、数据库)
- linux du | sort 命令查找磁盘占用大户
- web前端 - Vue常见问题汇总及解决方案
- ssd nvme sata_NVMe SSD与传统SATA SSD