Horspool字符串匹配算法

来源:互联网 发布:历史地理 书籍 知乎 编辑:程序博客网 时间:2024/06/07 01:16

horspool算法为字符串匹配算法,比较的时候从模式的最右边开始和文本中的字符进行一一标胶,如果全部匹配成功就完成了,但是如果遇到不一样的,我们不会像蛮力法那样才移动一格,根据不同情况移动步子不同,有以下几种情况。(四种情况从算法课本里抄出来的,O(∩_∩)O哈哈~)


1:假设在文本中,对齐模式最后一个字符的元素是字符c,如果模式中不存在c(在我们的例子中,c就是字母S),模式安全移动的幅度就是他的全部长度

文本:A D C……………… S……………………

模式:                 B A R E B R

移动:                                       B A R B E R


2:如果模式中存在c,但它不是模式的最好一个字符(在我们的例子中,c就是字母B),移动时应该把模式中最右边的c和文本中的c对齐:

文本:A D C……………… B……………………

模式:                 B A R E B R

移动:                         B A R B E R


3:如果c正好是模式中最后一个字符,但在模式中其他m-1个字符中不包含c,移动情况类似1,移动幅度为m

文本:A D C………… M B R……………………

模式:                 B A R E B R

移动:                                       B A R B E R


4:如果c是模式中的最好一个字符,而且在模式的前m-1个字符中也包含c,移动的情况类似于2:移动时应该把模式中前m-1个字符中的c和文本中的c对齐

文本:A D C……………… R……………………

模式:                 B A R E B R

移动:                             B A R B E R



所以说这个算法其实基本一直在判断模式的最后一个字母什么情况,我们可以建立一张表,比如这个模式遇见A的时候应该移动几部,遇见B的时候移动几步,还有空格,!,@#¥,等各种符号应该移动几步,很明显根据第一种情况就能猜到,比如模式是BAREBR,那说白了遇见除了BARE四个字母的其他全部字母,都应该移动6步,

我们只要把遇见BAER应该移动几步放入表中,其他元素均为6即可。


对于移动距离t(c)=模式的长度c(如果c不包含在模式的前m-1个字符中)

t(c)=模式前m-1个字符中最右边的c到模式最后一个字符的距离(其他情况下)


至于这个移动表怎么写,就是每个字母对应的移动步数,首先初始时所用元素对应的值都是模式长度m,然后对模式中的第j个字符(0<=J<=m-2),将它在表中应该移动步数改为m-1-j。还有一些细节没有说明,反正千言万语都在代码里了,代码注释我自己写的很多,本来还有很多细节想说出来的,但是语言表达能力不怎么好。先这样吧,等以后理解更加深刻了再来改改。



上边那个是表,就是每个字母应该移动多少步,下边是过程。


之后上代码,我在horspool类里写了相关的方法,主函数里调用了一下。

horspool类;

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace Horspool算法{    class Horspool    {        /* 输入: 模式p[0..m-1]以及一个可能出现字符的字母表         * 输出: 以字母表中字符为索引的数组table[0..size-1]          */        public int[] ShiftTable(char[] p, int m)        {                /*table是一个可能出现的字母表和它对应的应该移动步数,也就是某个字母应该                 * 移动多少步这么一个表,但并不需要dictionary集合来完成,因为字符都是可以                 * 转化为ASCALL码的,我们直接用每个不同的下标表示每个字母和符号即可,而值便是                 * 应该移动的步数                 */              int[] table = new int[127];//建立移动表            //首先移动将表中每个元素都置为m,m就是模式的长度            for (int i = 0; i < table.Length; i++)            {                table[i] = m;            }            /*移动表此时所以元素的值都是6,但是我们现在需要改变模式             * 中那几个字符对应的值,也就是说如果出现模式中的字符,我们             * 是不应该移动6格去的,而且模式中有可能出现相同字符的,比如             * BARBER,但是horspool算法是从模式右方进行匹配的,所以我们             * 赋值的时候应该从左往右去赋值,这样模式中字符对应的移动步数             * 的最后一次改写是在该字符最后一次出现的时候             */            for (int i = 0; i < m - 1; i++)            {                /*p []是char集合,p[i]对应是字母,循环的时候,比如模式                 * 是BARBER,那么首先P[i]='B',table[B]=6-1-0=5,然后                 * table[A]=6-1-1=4;table[R]=6-1-2=3;然后此时又是计算B了,                 * 这就是为什么我们这里要从左向右赋值的原因,这样B又被再次赋值,                 * 而此时的B是离右边最近的,table[B]=6-1-3=2,table[E]=6-1-4=1,                 */                table[p[i]] = m - 1 - i;                //执行完后此时真正形成一个移动表,表中元素包含全部ACALL码对应的字符                //所应该移动的步长            }            return table;        }        /*匹配过程*/        public int HorspoolMatching(char[] p, int m, char[] t, int n, int[] table)        {            int i = m - 1; //光标先定于模式最后一位            // 匹配模式字符串字符个数              int k = 0;            while (i < n)//n是文本串的长度            {                k = 0;            /*K用来计量此时匹配了几个,K<m则表示此时还没有匹配完,             * P[m-1-k]是模式中对应字符,t[i-k]是文本串中对应字符             * 如果相同则k++,继续对照前一个             */                while (k < m && p[m - 1 - k] == t[i - k])                    k++;                //当匹配个数等于模式串个数,返回下标                if (k == m) { return i - m + 1; }                //否则移动对应的table移动表需要移动的距离                else i = i + table[t[i]];            }            return -1;        }    }}
program.cs:

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace Horspool算法{    class Program    {        static void Main(string[] args)        {             Horspool h = new Horspool();                     // 取得模式串以及长度          char[] p = args[0].ToCharArray();          int m = p.Length;                     // 取得文本串以及长度          char[] t = args[1].ToCharArray();          int n = t.Length;                     int[] table = h.ShiftTable(p, p.Length);                     //找到返回的下标值          int index = h.HorspoolMatching(p, m, t, n, table);        Console.WriteLine(index); ;        Console.ReadKey();        }    }}

好了就先这样了。


0 0
原创粉丝点击