字符串查找算法中,最著名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore)。两个算法在最坏情况下均具有线性的查找时间。但是在实用上,KMP算法并不比最简单的c库函数strstr()快多少,而BM算法则往往比KMP算法快上3-5倍。但是BM算法还不是最快的算法,这里介绍一种比BM算法更快一些的查找算法。
  例如我们要在"substring
searching algorithm"查找"search",刚开始时,把子串与文本左边对齐,

substring searching algorithm
search
^

  结果在第二个字符处发现不匹配,于是要把子串往后移动。但是该移动多少呢?这就是各种算法各显神通的地方了,最简单的做法是移动一个字符位置;KMP是利用已经匹配部分的信息来移动;BM算法是做反向比较,并根据已经匹配的部分来确定移动量。这里要介绍的方法是看紧跟在当前子串之后的那个字符(上图中的'i')

  显然,不管移动多少,这个字符是肯定要参加下一步的比较的,也就是说,如果下一步匹配到了,这个字符必须在子串内。所以,可以移动子串,使子串中的最右边的这个字符与它对齐。现在子串'search'中并不存在'i',则说明可以直接跳过一大片,从'i'之后的那个字符(即‘n’)开始作下一步的比较,如下图:

substring searching algorithm
           search
         ^

  比较的结果,第一个字符就不匹配,再看子串后面的那个字符,是'r',它在子串中出现在倒数第三位,于是把子串向前移动三位,使两个'r'对齐,如下:

substring searching algorithm
              search

  哈!这次匹配成功了!回顾整个过程,我们只移动了两次子串就找到了匹配位置,是不是很神啊?!可以证明,用这个算法,每一步的移动量都比BM算法要大,所以肯定比BM算法更快。

下面是这个算法的c代码。注意我假设了每个字符的值都介于0-127之间(即纯ascii码)。

 #ifndef SUNDAY_H
#define SUNDAY_H /********************************************************
Sunday算法:
假设源字符串为src,匹配串为pattern。
如果src的某字符不匹配:
(1)该字符在pattern中,且在pattern中最右边的位置为n。那么
下次匹配直接移动pattern使得n的位置和该字符的位置对应的地方。
(2)该字符不在pattern中,显然没有比较的意义,则直接跳过去,
将pattern的头部移到与该字符下一个字符对应的位置。
*********************************************************/ #include <string.h>
#include <stdio.h> // 假设出现的字符都是0~127范围内的,即都是ascii字符
char *sunday(const char *src, char *pattern) {
if (NULL == src)
return NULL;
if (NULL == pattern)
return (char *)src; int len1, len2, shift[]; len1 = strlen(src);
len2 = strlen(pattern); // construct shitf table
for (int i = ; i < ; i++)
shift[i] = len2 + ; // 默认是移动len2+1,即直接跳过 // adjust shift table
const char *p;
for (p = pattern; *p; p++)
shift[*p] = len2 - (p - pattern); // p-pattern为字符相对于第一个元素的偏移量,len2-(p-pattern)则表示从右往左数的偏移量,即要移动的步数 const char *s, *pSrc = src;
// start search
while (pSrc + len2 <= src + len1) { // 如果pSrc + len2不越界(若越界,则说明src剩余未匹配的字符数量小于pattern的长度,则肯定不会匹配成功)
for (p = pattern, s = pSrc; *p; ++p, ++s)
if (*p != *s) // mistach
break;// break内循环 if ('\0' == *p) // found it!
return (char *)pSrc; pSrc += shift[pSrc[len2]]; // pSrc[len2]取出下一个需要匹配的字符,shift[pSrc[len2]]取出该字符需要让指针移动多少步
} return NULL;
} #endif

下面是main:

 #include "Sunday.h"

 int main() {
char *src = "", *patt = "";
char *ret = sunday(src, patt); printf("%s\n", ret); return ;
}

  代码最后:pSrc += shift[pSrc[len2]];这里。

举个例子来理解下,比如:

123456789

  237

那么4和7不匹配,len2就表示'5'这个位置,所以pSrc[len2]表示取出'5'这个字符。

所以pSrc下次就移动到'5'这个位置重新开始匹配了。

ref:http://operatingfocus.bokee.com/3557609.html

Sunday算法(字符串查找、匹配)的更多相关文章

  1. KMP 算法 & 字符串查找算法

    KMP算法 Knuth–Morris–Pratt algorithm 克努斯-莫里斯-普拉特 算法 algorithm kmp_search: input: an array of character ...

  2. C++ string 字符串查找匹配

    在写C++程序中,总会遇到要从一个字符串中查找一小段子字符串的情况,对于在C中,我们经常用到strstr()或者strchr()这两种方法.而对于C++的string,我们往往会用到find(). C ...

  3. mongodb 字符串查找匹配中$regex的用法

    官网地址:https://docs.mongodb.com/manual/reference/operator/query/regex/#regex-case-insensitive 举个例子来说:现 ...

  4. KMP算法字符串查找子串

    题目: 经典的KMP算法 分析: 和KMP算法对应的是BF算法,其中BF算法时间复杂度,最坏情况下可以达到O(n*m),而KMP算法的时间复杂度是O(n + m),所以,KMP算法效率高很多. 但是K ...

  5. python多目录字符串查找匹配

    1. 需求来自于实际工作: 需要处理一批服务器上运行的redis实例,每个redis实例可能有密码,也可能没有,有密码的,密码配置格式一定是: requirepass XXXXX # XXXX是密码 ...

  6. 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)

    字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...

  7. 字符串匹配算法之Sunday算法

    字符串匹配查找算法中,最着名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore).两个算法在最坏情况下均具有线性的查找时间.但是在实用上,KMP算法并不比最简 ...

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

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

  9. Rabin-Karp指纹字符串查找算法

    首先计算模式字符串的散列函数, 如果找到一个和模式字符串散列值相同的子字符串, 那么继续验证两者是否匹配. 这个过程等价于将模式保存在一个散列表中, 然后在文本中的所有子字符串查找. 但不需要为散列表 ...

随机推荐

  1. ORA-00911无效字符报错

    今天在修改缺陷时遇到一个问题,更新数据库字段时一直报错:ORA-00911.sql脚本如下: '; '; '; 该脚本在数据库中可以执行,但是从程序中去访问数据库修改值时就会报错. 报错的原因在于,更 ...

  2. Linux 下Git的安装和配置

    Git是分布式的版本控制系统,实际上是不需要固定的服务器的,Git与svn的最大区别是,它的使用流程不需要联机,可以先将对代码的修改,评论,保存在本机.等上网之后,再实时推送过去.同时它创建分支与合并 ...

  3. ES6入门之set和map

    Set ES6提供了新的数据结构Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化. // 例一 var set = ne ...

  4. PHP的面向对象编程

    面向对象编程的概念: 不同的作者之间说法可能不一样,但是一个OOP语言必须有以下几方面: 抽象数据类型和信息封装 继承 多态 在PHP中是通过类来完成封装的: <?php class Somet ...

  5. Case 架构的实际应用-2

    Test Plan in TestLink 1. For new release, we will create 2 test plans for each project 2. 1st test p ...

  6. nova读取配置文件流程

          在我们安装nova的过程中,设置它的配置文件/etc/nova/nova.conf是必不可少的一步.配置好nova.conf文件,nova-compute.nova-network等服务才 ...

  7. J2EE开发之常用开源项目介绍

    主要就我所了解的J2EE开发的框架或开源项目做个介绍,可以根据需求选用适当的开源组件进行开发.主要还是以Spring为核心,也总结了一些以前web开发常用的开源工具和开源类库 1持久层: 1)Hibe ...

  8. HTML & CSS 小总结

    1. web 主机代理商 web hosting company, 让他们的服务器为你的页面服务2. 选择网站名字 例如: www.1234.com3. 寻找 把文件从电脑传到主机的途径4. 把新网站 ...

  9. jsp之jsp基础

    1. Jsp生命周期 客户端第一次请求->web容器把jsp文件转译为servlet源文件(java)->编译为class文件->载入class文件生成servlet对象 2. Js ...

  10. UVa 1149 (贪心) Bin Packing

    首先对物品按重量从小到大排序排序. 因为每个背包最多装两个物品,所以直觉上是最轻的和最重的放一起最节省空间. 考虑最轻的物品i和最重的物品j,如果ij可以放在一个包里那就放在一起. 否则的话,j只能自 ...