Horspool算法-字符串匹配

不得不说ACM哪怕是没有结果,对于算法能力的训练是毋庸置疑的……

因为老师划了重点,所以讲一下horspool的字符串匹配算法的原理吧。

先声明几个概念,被找的字符串称为匹配串,要找的字符串被称为模式串,当前和模式串相匹配的匹配串的子串被称为匹配子串(废话

在朴素算法中,我们要找一个匹配串是否存在模式串,例如HuangZhi is a genius的匹配串串和ChengJinSen的模式串,那么我们一开始用的方法是用:

HuangZhi is(11 character)

去匹配:

ChengJinSen(11 character)

如果每个字母都相等,那么我们就认为这个模式找到了。

但是这个算法的效率是多少呢,假设匹配串的长度为N,模式串的长度为m,那么易证时间效率为:O(n*m),在很多时候这个效率都是很慢的。

而Horspool算法(在我看来)是有这样一个基本思想:如果我提前知道了这个步骤是可以跳过的,那我就可以不用去验证了。

我们拿saber和archer作为模式串和匹配串好了:

archer

saber

很明显,在初次对齐的时候,其并不相等,而且我们注意到了,此次匹配串对应的子串是:arche,而最后一个字母是e.

那么很明显的,假如我们一个个移动下去,直到模式串的下一个e为止,都不可能达到匹配的结果。

这里e就是下一个,所以我们把saber稍稍的改一下,改成sebar,这时候就会发现,假设你一个个挪,到e之前的所有都不可能和arche里的e匹配,所以这里我们完全可以直接把e挪到arche的e的位置,然后在进行匹配计算,这样就节省了不少的时间。也就是说,跳过e到模式串最后一个字母之间的距离。

以上的情况,可以归纳为情况1,即匹配子串的最后一个在模式串中出现过,且不是模式串的最后一个字母(最后的特殊性会讲到)

那么,假设最后一个字符在模式串里从来没有出现过呢?那这样,假设一个个移,每一个都必然得不到匹配结果,直到该字符不在匹配子串中,如此,则是直接跳过整个子串的长度。

以上情况归为情况2,匹配子串的最后一个字母没有在模式串里出现过,且不是模式串的最后一个字母。

好了,为什么上面要提到模式串的字母呢?因为这个查询方法存在一个问题,假设匹配子串的最后一个字母在模式串中出现过,且为模式串的最后一位呢?那这样就要分成两种情况来讨论,

1,是模式串的最后一位字母在模式串中唯一,那这样就类似于情况2,直接跳过这个匹配子串最后字母的匹配,即跳过字符长度。这个我们姑且称为情况3。

2,是该字母在模式串中不唯一,那这样就仿照情况二,找到离模式串结尾最近的,且同样是这个字母的字母的位置,并跳转以后匹配。这个我们称为情况4

然后是这个算法的计算机实现,总结了下上述规律,我们发现这个模式串跳转的机制,可以不用每次查找模式串中是否有同样的值,而用预处理的方式来实现,根据情况一二的总结,我们得出,模式串中存在的字母,向右找到其最贴近模式串结尾的同样的字母,并把其离结尾的位置存下,方便应用,若不存在,则直接跳转模式串长度,为了方便,我们也把它存下来,不过跳转长度设为模式串长度。根据情况3,4的总结,我们得出,最后一个字母不应纳入上述的计算。

附带试验用算法:

#include<iostream>

#include<algorithm>

#include<vector>

#include<map>

#include<string>

#define INF 0x3f3f3f3f

using namespace std;

int main() {
     string M, P;
     cin >> M >> P;
     map<char, int>NEXT;
     for (int i = 0; i < 26; i++)
         NEXT[‘a‘ + i] = P.size();
     for (int i = 0; i < 26; i++)
         NEXT[‘A‘ + i] = P.size();
     for (int i = 0; i < P.size() - 1; i++)
         NEXT[P[i]] = P.size() - i-1;
     int space = 0;
     for (int i = 0; i <= M.size()-P.size();)
     {
         space = i;
         cout << M << endl;
         for (int i = 0; i < space; i++)
             cout << " ";
         cout << P << endl << "_________________________________" << endl;
         if (M.substr(i, P.size()) == P)
             cout << "找到匹配串" << endl;
         i += NEXT[M[i + P.size() - 1]];
     }

}

时间: 2024-10-11 20:42:54

Horspool算法-字符串匹配的相关文章

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

前言 本节介绍Knuth-Morris-Pratt字符串匹配算法(简称KMP算法).该算法最主要是构造出模式串pat的前缀和后缀的最大相同字符串长度数组next,和前面介绍的<朴素字符串匹配算法>不同,朴素算法是当遇到不匹配字符时,向后移动一位继续匹配,而KMP算法是当遇到不匹配字符时,不是简单的向后移一位字符,而是根据前面已匹配的字符数和模式串前缀和后缀的最大相同字符串长度数组next的元素来确定向后移动的位数,所以KMP算法的时间复杂度比朴素算法的要少,并且是线性时间复杂度,即预处理时间复

算法——字符串匹配之BM算法

前言 Boyer-Moore算法是一种基于后缀匹配的模式串匹配算法(简称BM算法),后缀匹配就是模式串从右到左开始比较,但模式串的移动依然是从左到右的.在实践中,BM算法效率高于前面介绍的<KMP算法>,算法分为两个阶段:预处理阶段和搜索阶段:预处理阶段时间和空间复杂度都是是O(m+sigma),sigma是字符集大小,一般为256:在最坏的情况下算法时间复杂度是O(m*n):在最好的情况下达到O(n/m). BM算法实现 BM算法预处理过程 BM算法有两个规则分别为坏字符规则(Bad Cha

KMP算法字符串匹配

对于暴力搜索法,当搜索词对应的字符与字符串中的字符不匹配时.将搜索词整个后移一位,再从头逐个比较.这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍. 应用KMP算法之后,则有: 移动位数=已匹配的字符数?对应的部分匹配值 "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度. KMP算法实现代码如下: void prefixFun(char *pattern, int *preFun)

算法——字符串匹配之有限自动机算法

前言 上篇文章介绍<Rabin-Karp字符串匹配算法>,这里介绍有限自动机(Finite Automata)字符串匹配算法,有限自动机(Finite Automata)字符串匹配算法最主要的是计算出转移函数.即给定一个当前状态k和一个字符x,计算下一个状态:计算方法为:找出模式pat的最长前缀prefix,同时也是pat[0...k-1]x(注意:字符串下标是从0开始)的后缀,则prefix的长度即为下一个状态.匹配的过程是比较输入文本子串和模式串的状态值,若相等则存在,若不想等则不存在.有

算法——字符串匹配之Rabin-Karp算法

前言 Rabin-Karp字符串匹配算法和前面介绍的<朴素字符串匹配算法>类似,也是对应每一个字符进行比较,不同的是Rabin-Karp采用了把字符进行预处理,也就是对每个字符进行对应进制数并取模运算,类似于通过某种函数计算其函数值,比较的是每个字符的函数值.预处理时间O(m),匹配时间是O((n-m+1)m). Rabin-Karp算法实现 伪代码: Rabin_Karp_search(T, P, d, q) n = T.length; m = P.length; h = d^(m-1)mo

KMP算法---字符串匹配

算法细节详见点击打开链接和点击打开链接 #include <stdio.h> #include <stdlib.h> #define N 7 #define M 15 void showpset(int* a); void cal_pset(char* a, int* p,int n); int KMP(char* a,char* b,int* P); int main(void) { char a[M]={'a','b','a','c','a','b','a','a','b','

KMP算法 - 字符串匹配的简单运用 --- HDU 1711

Number Sequence Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11606    Accepted Submission(s): 5294 Problem Description Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b

数据结构与算法 -- 字符串匹配

1.Trie树 public class TrieTree { private TrieNode root = new TrieNode('/');//存储无意义字符 //往Trie树中插入一个字符串 public void insert(char[] text) { TrieNode p = root; for(int i=0; i<text.length; i++) { int index = text[i] - 'a'; if(p.children[index] == null) { Tr

swift算法实践(3)-KMP算法字符串匹配

    版权声明:本文为博主原创文章,未经博主允许不得转载.