字符串匹配查找算法中,最着名的两个是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算法的更多相关文章

  1. 字符串匹配算法之Sunday算法(转)

    字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是Ω(m*n),也就是达到了字符串匹配效率的下限.于是后来人经过研究 ...

  2. 字符串匹配算法:Sunday算法

    背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是\(Ω(m*n)\),也就是达到了字符串匹配效率的下限.于是后来人经过研究,构造出了著名的KMP算法 ...

  3. 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!

    前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...

  4. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  5. 字符串匹配算法之BM算法

    BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...

  6. Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化

    1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...

  7. 字符串匹配算法之————KMP算法

    上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...

  8. 字符串匹配算法之kmp算法

    kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...

  9. 字符串匹配算法(二)-BM算法详解

    我们在字符串匹配算法(一)学习了BF算法和RK算法,那有没更加高效的字符串匹配算法呢.我们今天就来聊一聊BM算法. BM算法 我们把模式串和主串的匹配过程,可以看做是固定主串,然后模式串不断在往后滑动 ...

随机推荐

  1. Delphi String 与wideString 的完美转换

    一般来说,String与widestring 的转换是系统自动进行的,但是,考虑如下字符串 s:=#2+#3+#0+#10+#0+#1+#164+#59;,显然S的长度为8,然后执行如下代码 var ...

  2. Linux 下 的 cc 和 gcc

    在Linux下一会看到cc,另一会又看到gcc,感觉又点混乱的样子.它们是同一个东西么,有啥区别呢? 一分为二地看: 首先,如果讨论范围在Unix和Linux之间,那么cc和gcc不是同一个东西.cc ...

  3. 计算机语言的发展(the history of computer's language)

    第一部分 计算机语言的分类: 机器语言:直接用二进制代码指令表达的计算机语言,指令是用0和1组成的一串代码.例如:1011011000000000,表示加法.可以直接执行. 汇编语言:汇编指令集.伪指 ...

  4. POJ_3356——最短编辑距离,动态规划

    Description Let x and y be two strings over some finite alphabet A. We would like to transform x int ...

  5. DLL入门浅析(2)——如何使用DLL

    转载自:http://www.cppblog.com/suiaiguo/archive/2009/07/20/90621.html 上文我简单的介绍了如何建立一个简单DLL,下面再我简单的介绍一下如何 ...

  6. 使用 Docker 容器应该避免的 10 个事情

    当你最后投入容器的怀抱,发现它能解决很多问题,而且还具有众多的优点: 第一:它是不可变的 – 操作系统,库版本,配置,文件夹和应用都是一样的.您可以使用通过相同QA测试的镜像,使产品具有相同的表现. ...

  7. 深入理解object C中复制对象的用法(二)

    第五.对象的自定义拷贝 对象拥有复制特性,必须实现NSCopying,NSMutableCopying协议,实现该协议的copyWithZone方法和mutableCopyWithZone方法 深拷贝 ...

  8. BitmapFactory.decodeByteArray() 返回null,分析与解决

    问题描述:用android自带的Camera获取图片,上传至远程数据库中(mysql),以BLOB格式存储, 但在提取图片时,始终无法在android界面显示,示例代码如下: .....  .... ...

  9. Struts2框架具体解释

    在Struts2的Model-View-Controller模式实现下面五个核心组件: 动作-Actions 拦截器-Interceptors 值栈/OGNL 结果/结果类型 视图技术 Struts ...

  10. Android消息机制(2)

    在Android 中,线程内部或者线程之间进行信息交互时经常会使用消息,这些基础的东西如果我们熟悉其内部的原理,将会使我们容易.更好地架构系统,避免一些低级的错误. 下面我们分析下程序的运行过程: 1 ...