字符串匹配 — Horspool

蛮力法进行字符串匹配的缺点在于每次失配后模式只向后移动一个位置。想要提高算法效率,就必须在不错过文本中一个匹配子串风险的前提下,尽量增大模式向后移动的幅度。Horspool就是这样一种算法之一,它的思想要比KMP算法容易。它采用了输入增加技术:对模式进行预处理得到一些信息,把这些信息存储在表中,当文本和模式进行匹配时就会用到这些信息。Horspool的匹配过程是从右向左进行的,在匹配过程中会出现以下四种情况:

情况1

文本:x x x x A x x x x x

模式:    x x B

最后一个字符失配,且模式中不存在文本中的失配字符A,那么模式可以移动的幅度就是它的长度,这里是把模式向后移动3个位置,如下所示:

文本:x x x x A x x x x x

模式:          x x B

情况2

文本:x x x x A x x x x x

模式:    A x B

最后一个字符失配,且模式中存在文本中的失配字符A,这时应该把模式最右边的A和文本的A对齐,如下所示:

文本:x x x x A x x x x x

模式:        A x B

情况3

文本:x x x B A x x x x x

模式:    x W A

最后一个字符A相匹配,且模式中剩下的字符都不存在A,那么情况类似于1,移动幅度等于模式的全部长度,如下所示:

文本:x x x B A x x x x x

模式:          x W A

情况4

文本:x x x B A x x x x x

模式:    A W A

最后一个字符A相匹配,且模式中剩下的字符中存在A,那么情况类似于2,移动模式使二者对齐,如下所示:

文本:x x x B A x x x x x

模式:        A W A

从上述过程可以看出,算法的关键是要知道文本中的某个字符(上述过程是字符A)是否在模式中存在,存在的话距模式最后一个字符相差多远。这些信息就是我们要存储在表中的信息。可以以文本中出现的每个字符为c自变量,发生失配时模式可以安全移动的最大距离为函数t(c),得到如下映射:

  • 如果c不包含在模式的前m-1个字符中,则t(c) = 模式长度m
  • t(c) = 模式前m-1个字符中最右边的c到模式最后一个字符的距离

例如有模式ABCDE,那么在文本的所有字符之中,t(D) = 1,t(C) = 2,t(B) = 3,t(A) = 4,其余字符对应的函数均为模式长度5.对于这种函数映射,用C++的map容器再适合不过了。

以下是完整代码:

#include <iostream>
#include <string>
#include <map>
#include <vector>

using namespace std;

void Get_Next(const string &text, const string &pattern, map<char, int> &next)
{
    int text_len = text.size();
    int pattern_len = pattern.size();

    for (int i = 0; i < text_len; i++)
        next.insert(make_pair(text[i], pattern_len));

    for (int i = 0; i < pattern_len - 1; i++)
        next[pattern[i]] = pattern_len - 1 - i;
}

void Horspool(const string &text, const string &pattern, vector<int> &result)
{
    int text_len = text.size();
    int pattern_len = pattern.size();
    map<char, int> next;    // 使用map容器记录移动表

    Get_Next(text, pattern, next);

    for (int i = pattern_len - 1; i < text_len; /* NULL */)
    {
        int text_pos = i;
        int pattern_pos;
        for (pattern_pos = pattern_len - 1; pattern_pos >= 0; /* NULL */)
        {
            if (text[text_pos] == pattern[pattern_pos])
            {
                text_pos--;
                pattern_pos--;
            }
            else
            {
                i += next[text[i]];   // i = 文本中对齐模式最后一个字符的位置
                break;
            }
        }
        if (pattern_pos <= 0)
        {
            result.push_back(i - pattern_len + 1);  // 完全匹配时的起始位置
            i++;
        }
    }
}

int main()
{
    string text = "hello world good google Nestle people google hello this is a test google";
    string pattern = "google";
    vector<int> result;

    Horspool(text, pattern, result);

    int cnt = 1;
    for (vector<int>::iterator iter = result.begin(); iter != result.end(); ++iter)
        cout << "match " << cnt++ << " = " << *iter << endl;

    system("pause");
    return 0;
}

运行结果:

对于随机文本,Horspool算法的效率为Θ(n),n为文本长度。

参考:

《算法设计与分析基础》 P194-P197.

字符串匹配 — Horspool

时间: 2024-11-04 11:33:17

字符串匹配 — Horspool的相关文章

字符串匹配之horspool算法(简化的BM算法)

前面介绍在BF,KMP这些算法的时候老是提到BM这个东西,究竟这什么东西,有啥高深的,这些问题我们如今不去考虑.不知道,认真读前几篇文章的读者有没有发现前面的算法都是从模式串的前面開始匹配的,那我们就想能不能从模式串的后面開始匹配了? 答案肯定是能够的.所以这就有了我们今天的这篇文章Horspool算法,这个算法是基于字符串后缀的匹配算法. 在上一篇文章中,我们学习了一个概念叫好字符(又叫好后缀),大家都知道有好必有坏吧,所以我们今天再来学习一个概念-----坏字符. 一.坏字符与模式串滑动 坏

时空权衡之字符串匹配中的输入增强技术

字符串匹配的蛮力的算法: 对于字符数为n的文本,模式(要匹配的字符串)字符为m的字符串,简单的从左到右比较模式和文本中每一对相应的字符,,如果不匹配,模式向右移一格,再进行下一轮的尝试. 这样尝试的最大次数为n-m+1次,模式进行m次比较,这样比较次数一共是m(n-m+1)=O(nm),次,对于随机的自然文本,它的平均效率为O(n+m) 使用输入增强的思想:对模式进行预处理以得到它的一些信息,把这些信息储存在表中,然后在给定文本中实际查找模式时使用这些信息. 以下是这种思维下的两种算法: 一.H

uva:10340 - All in All(字符串匹配)

题目:10340 - All in All 题目大意:给出字符串s和t,问s是否是t的子串.s若去掉某些字符能和t一样,那么t是s的子串. 解题思路:匹配字符.t的每个字符和s中的字符匹配.注意这里的字符数组大小要开大点. 代码: #include <stdio.h> #include <string.h> const int N = 1000005; char s[N], t[N]; bool match () { int i = 0; int lens = strlen(s);

CCF 字符串匹配

问题描述 试题编号: 201409-3 试题名称: 字符串匹配 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符:当选项关闭时,表示同一个字母的大写和小写看作相同的字符. 输入格式 输入的第一行包含一个字符串S,由大小写英文字母组成. 第二行包含一个数字,表示大小写敏感的选项,当数字为0时表示大小写不敏感,当数字为1时表示大小

字符串匹配的KMP算法

html, body { font-size: 15px; } body { font-family: Helvetica, "Hiragino Sans GB", 微软雅黑, "Microsoft YaHei UI", SimSun, SimHei, arial, sans-serif; line-height: 1.6; color: ; background-color: ; margin: 0; padding: 16px 20px; } h1, h2, h

字符串匹配与KMP算法笔记

>>字符串匹配问题 字符串匹配问题即在匹配串中寻找模式串是否出现, 首先想到的是使用暴力破解,也就是Brute Force(BF或蛮力搜索) 算法,将匹配串和模式串左对齐,然后从左向右一个一个进行比较, 如果不成功则模式串向右移动一个单位,直到匹配成功或者到达匹配串最后仍然不成功,返回失败. 很明显,这种算法有很多的地方可以优化,假设要搜索的串为S,长度为n,要匹配的串为M,长度为m,时间复杂度为O(nm). >>KMP算法 Knuth-Morris-Pratt算法以三个发明者命名

KMP算法解决字符串匹配

该算法由D.E.Knuth ,J.H.Morris和 V.R.Pratt提出,用于解决字符串匹配问题. 思想: 设目标串(主串)为s,模式串为t ,并设i指针和j指针分别指示目标串和模式串中正待比较的字符,设i和j的初值均为0.若有s[i]=t[j],则i和j分别加1.否则,i不变,j退回到j=next[j-1]的位置,再比较s[i]和t[j],若相等,则i和j分别加1.否则,i不变,j再次退回到j=next[j]的位置,依此类推.直到下列两种可能: 1. 模式串t中的字符全部匹配,则出现频率+

字符串匹配 【kmp】

字符串匹配 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 214 Solved: 81 Description 给你两个字符串A,B,请输出B字符串在A字符串中出现了几次. Input 多组测试数据,每组输入两个字符串.字符串的长度 <= 1000000. Output 输出B在A中出现的次数. Sample Input aaa aa Sample Output 1 子串在母串中出现的次数,串不重叠 #include <stdio.h> #

九度机试 题目1165:字符串匹配 2008年北京航空航天大学计算机研究生机试真题

题目1165:字符串匹配 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2497 解决:858 题目描述: 读入数据string[ ],然后读入一个短字符串.要求查找string[ ]中和短字符串的所有匹配,输出行号.匹配字符串.匹配时不区分大小写,并且可以有一个用中括号表示的模式匹配.如"aa[123]bb",就是说aa1bb.aa2bb.aa3bb都算匹配. 输入: 输入有多组数据. 每组数据第一行输入n(1<=n<=1000),从第二行开始输入n个字符串(