字符串匹配算法之Sunday算法
字符串匹配查找算法中,最着名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore)。两个算法在最坏情况下均具有线性的查找时间。但是在实用上,KMP算法并不比最简单的C库函数strstr()快多少,而BM算法则往往比KMP算法快上3-5倍(未亲身实践)。但是BM算法还不是最快的算法,这里介绍一种比BM算法更快一些的查找算法Sunday算法。
Sunday算法的思想和BM算法中的坏字符思想非常类似。差别只是在于Sunday算法在匹配失败之后,是取目标串中当前和Pattern字符串对应的部分后面一个位置的字符来做坏字符匹配。
当发现匹配失败的时候就判断母串中当前偏移量+Pattern字符串长度+1处(假设为K位置)的字符在Pattern字符串中是否存在。如果存在,则将该位置和Pattern字符串中的该字符对齐,再从头开始匹配;如果不存在,就将Pattern字符串向后移动,和母串k+1处的字符对齐,再进行匹配。重复上面的操作直到找到,或母串被找完结束托福答案 www.yztrans.com
动手写了个小例子来实现以下这个算法。
在代码中,实现了两种字符串匹配算法,一种是Sunday方式,一种是普通的每次移动一位的方式,二者的效率对比在main函数中有,都是纳秒级别。算法的详细步骤,在代码中已经添加了相应的注释。关于BM算法,下次空了再一起对照着分析 www.lefeng123.com
1 import java.util.HashMap;
2 import java.util.LinkedList;
3 import java.util.List;
4 import java.util.Map;
5
6 /**
7 * @author Scott
8 * @date 2013年12月28日
9 * @description
10 */
11 public class SundySearch {
12 String text = null;
13 String pattern = null;
14 int currentPos = 0;
15
16 /**
17 * 匹配后的子串第一个字符位置列表
18 */
19 List<Integer> matchedPosList = new LinkedList<Integer>();
20
21 /**
22 * 匹配字符的Map,记录改匹配字符串有哪些char并且每个char最后出现的位移
23 */
24 Map<Character, Integer> map = new HashMap<Character, Integer>();
25
26 public SundySearch(String text, String pattern) {
27 this.text = text;
28 this.pattern = pattern;
29 this.initMap();
30 };
31
32 /**
33 * Sunday匹配时,用来存储Pattern中每个字符最后一次出现的位置,从左到右的顺序
34 */
35 private void initMap() {
36 for (int i = 0; i < pattern.length(); i++) {
37 this.map.put(pattern.charAt(i), i);
38
39 }
40 }
41
42 /**
43 * 普通的字符串递归匹配,匹配失败就前进一位
44 */
45 public List<Integer> normalMatch() {
46 //匹配失败,继续往下走
47 if (!matchFromSpecialPos(currentPos)) {
48 currentPos += 1;
49
50 if ((text.length() - currentPos) < pattern.length()) {
51 return matchedPosList;
52 }
53 normalMatch();
54 } else {
55 //匹配成功,记录位置
56 matchedPosList.add(currentPos);
57 currentPos += 1;
58 normalMatch();
59 }
60
61 return matchedPosList;
62 }
63
64 /**
65 * Sunday匹配,假定Text中的K字符的位置为:当前偏移量+Pattern字符串长度+1
66 */
67 public List<Integer> sundayMatch() {
68 // 如果没有匹配成功
69 if (!matchFromSpecialPos(currentPos)) {
70 // 如果Text中K字符没有在Pattern字符串中出现,则跳过整个Pattern字符串长度
71 if ((currentPos + pattern.length() + 1) < text.length()
72 && !map.containsKey(text.charAt(currentPos + pattern.length() + 1))) {
73 currentPos += pattern.length();
74 }else {
75 // 如果Text中K字符在Pattern字符串中出现,则将Text中K字符的位置和Pattern字符串中的最后一次出现K字符的位置对齐
76 if ((currentPos + pattern.length() + 1) > text.length()) {
77 currentPos += 1;
78 } else {
79 currentPos += pattern.length() - (Integer) map.get(text.charAt(currentPos + pattern.length()));
80 }
81 }
82
83 // 匹配完成,返回全部匹配成功的初始位移
84 if ((text.length() - currentPos) < pattern.length()) {
85 return matchedPosList;
86 }
87
88 sundayMatch();
89 }else {
90 // 匹配成功前进一位然后再次匹配
91 matchedPosList.add(currentPos);
92 currentPos += 1;
93 sundayMatch();
94 }
95 return matchedPosList;
96 }
97
98 /**
99 * 检查从Text的指定偏移量开始的子串是否和Pattern匹配
100 */
101 public boolean matchFromSpecialPos(int pos) {
102 if ((text.length()-pos) < pattern.length()) {
103 return false;
104 }
105
106 for (int i = 0; i < pattern.length(); i++) {
107 if (text.charAt(pos + i) == pattern.charAt(i)) {
108 if (i == (pattern.length()-1)) {
109 return true;
110 }
111 continue;
112 } else {
113 break;
114 }
115 }
116
117 return false;
118 }
119
120 public static void main(String[] args) {
121 SundySearch sundySearch = new SundySearch("hello 啊啊 阿道夫 adfsadfklf adf234masdfsdfdsfdsfdsffwerwrewrerwerwersdf2666sdflsdfk", "adf");
122
123 long begin = System.nanoTime();
124 System.out.println("NormalMatch:" + sundySearch.normalMatch());
125 System.out.println("NormalMatch:" + (System.nanoTime() - begin));
126
127 begin = System.nanoTime();
128 System.out.println("SundayMatch:" + sundySearch.sundayMatch());
129 System.out.println("SundayMatch:" + (System.nanoTime() - begin));
130
131 }
132 }
运行结果:
NormalMatch:[13, 17, 24]
NormalMatch:313423
SundayMatch:[13, 17, 24]
SundayMatch:36251
字符串匹配算法之Sunday算法的更多相关文章
- 字符串匹配算法之Sunday算法(转)
字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是Ω(m*n),也就是达到了字符串匹配效率的下限.于是后来人经过研究 ...
- 字符串匹配算法:Sunday算法
背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是\(Ω(m*n)\),也就是达到了字符串匹配效率的下限.于是后来人经过研究,构造出了著名的KMP算法 ...
- 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!
前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...
- 字符串匹配算法之 kmp算法 (python版)
字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...
- 字符串匹配算法之BM算法
BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...
- Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化
1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...
- 字符串匹配算法之————KMP算法
上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...
- 字符串匹配算法之kmp算法
kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...
- 字符串匹配算法(二)-BM算法详解
我们在字符串匹配算法(一)学习了BF算法和RK算法,那有没更加高效的字符串匹配算法呢.我们今天就来聊一聊BM算法. BM算法 我们把模式串和主串的匹配过程,可以看做是固定主串,然后模式串不断在往后滑动 ...
随机推荐
- POJ 1637 混合图欧拉回路
先来复习一下混合图欧拉回路:给定一张含有单向边和双向边的图,使得每一点的入度出度相同. 首先对于有向边来说,它能贡献的入度出度是确定的,我们不予考虑.对于无向图,它可以通过改变方向来改变两端点的出入度 ...
- COJ 0015 20602铁轨
传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=15 20602铁轨 难度级别:B: 运行时间限制:1000ms: 运行空间限 ...
- 深入JS系列学习2
今天看和学习了深入理解JS系列2.3.4.5,更加明白了函数声明和表达式的区别,自执行函数和立即执行函数,js强大的原型链继承,js中对象的想过写法,modules模式等. 在ECMAScript中, ...
- git bash中避免在push时反复输入用户名和密码
我用的是windows系统,这几天学着使用git时发现每次使用git push时每次都要输入一遍用户名和密码,感觉特烦,特意上网查了下,找到了简化方法.虽然不是原创,但至少算是加了点自己的心得和经验吧 ...
- 「Githug」Git 游戏通关流程
Githug 他喵的这是个啥!?难道不是 GitHub 拼错了么,和 Git 什么关系? 和游戏又有什么关系? 其实,他的元身在这里:https://github.com/Gazler/githug ...
- Redis需要你来做的算法优化
阅读一个优秀的Server内核实现,早期的代码比后期的代码要好得多.因为在早期的代码里,你可以学习到一个黑客级别的程序猿到底在思考什么.同时,你能看到他哪里写得差劲,以及后来是怎么优化的. 如果你一心 ...
- JSP学习笔记(一):JDK的安装及环境变量的配置
一.JDK的安装. JDK可以在Oracle(甲骨文)的官网下载,连接地址:http://www.oracle.com/technetwork/java/javase/downloads/index- ...
- Dockerfile制作sshd镜像
For Centos Shell脚本: # vim Dockerfile # mkdir /data01/sshd # vi Dockerfile # sshd # # VERSION 0.0.2 F ...
- Unity3D AssentStore 下载的package存放目录(WinXP,Win8,Mac OS X)
网上找到如下: Windows 8,C:\Users\<你的用户名>\AppData\Roaming\Unity\Asset Store Mac OS X,~/Library/Unity/ ...
- 持久化API(JPA)系列(三)实体Bean的开发技术-建立与数据库的连接
在EJB 2.x中.EJB有3种类型的Bean.各自是会话Bean(Session Bean).消息驱动Bean(Message-Driven Bean)和实体Bean(Entity Bean). 随 ...