字符串搜索算法(二)Sunday算法

Sunday算法是Daniel M.Sunday于1990年提出的一种非常高效的字符串搜索算法。其与其他搜索算法核心思想一样,都是跳过尽可能多的字符。但是Sunday算法更容易理解,算法更简单。
Sunday算法的跳跃规则是,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在匹配串中出现则直接跳过,即移动步长= 匹配串长度+1;否则,同BM算法一样其移动步长=匹配串中最右端的该字符到末尾的距离+1。
可能规则比较拗口,请看例子。

首先使pattern字符串与text字符串左侧对齐,同时从左向右依次匹配:
 

上图中,首先第一位的A匹配成功,第二位的B与text中的C不匹配。当出现不匹配的时候,就去看pattern长度对应的text串位置的下一位,图中蓝色的位置,由于这个位置是D,不出现在pattern串中,(因为这个时候可知,pattern向后移动1,2,3位都会与D去比较,D不在pattern中,显然他们是不会匹配成功的)那么我们可以直接跳到D字符的下一个字符,与之对齐。如下图



看图中,A与B不匹配,再看pattern后一位(蓝色)B,B存在于pattern串中,这个时候套用规则:移动步长=pattern串中最右端的该字符到末尾的距离+1,其实实际上是把这两个相同的字符对齐罢了。如下图B与B对齐:


接着从头再次匹配,发现A与M仍然不匹配。这个时候继续看pattern最后一位对应的下一位,下图中的Z,依然不存在于pattern串中,pattern串可以直接跳过Z

  

跳到Z后边之后,如下图,发现匹配。
匹配完成。

回过头来再看跳跃规则。
如果发生不匹配,则看pattern最后个位置加1的text串位置的字符,是否在pattern中。
1,不在pattern中,字符直接跳到这个字符后边。
2,在pattern中,则直接使pattern最右侧的这个字符与text串中这个字符对齐。

假设text串,pattern串中都是ASCII字符。为了可以快速的获取一个字符是否存在于pattern中,则可以建立一个数组,存储pattern中每个字符在pattern的位置。以ASCII码为索引,以该字符出现的位置为值。例如第一个字符A的ASCII码为65,那么数组中第66位置为0。所以使用的时候可以根据该字符ASCII码返回在pattern中的位置。不存在返回-1.

可以写出以下JAVA程序。详细看注释。
public class Sunday {
    /**
     * Sunday搜索
     * @param text 待搜索串
     * @param pattern 模式串
     * @return
     */
    public static int sundaySearch(String text, String pattern) {
        int textLen = text.length(), patternLen = pattern.length();
        //初始化pattern位置数组
        int[] occ = sundayInitOcc(pattern);
        //跳跃的步数
        int jump = 0;
        for (int i = 0; i <= textLen - patternLen; i += jump) {
            int j = 0;
            //用pattern字符与text字符挨个匹配
            while (j < patternLen && text.charAt(i + j) == pattern.charAt(j))
                j++;
            if (j == patternLen)//此时匹配成功
                return i;

            //此时不匹配
            //主要看问号后边计算跳跃步数,pattern长度减去pattern对应下一个字符位置就是要跳跃距离,由于occ数组中不存在为-1,巧妙合并了两种情况
            jump = i + patternLen < textLen ? patternLen - occ[text.charAt(i + patternLen)] : 1;
        }
        return -1;
    }

    /**
     * 初始化occ数组,数组中存储pattern字符串中每个字符在pattern中出现的位置
     * 索引为ASCII码,内容为在pattern的位置,出现相同字符,靠后位置的覆盖前边的,不存在的字符在pattern位置为-1
     * @param p
     * @return
     */
    public static int[] sundayInitOcc(String p) {
        int[] occ = new int[128];
        for (int i = 0; i < occ.length; i++)
            occ[i] = -1;
        for (int i = 0; i < p.length(); i++)
            occ[p.charAt(i)] = i;
        return occ;
    }
}


参考:
D.M. Sunday: "A Very Fast Substring Search Algorithm". Communications of the ACM, 33, 8, 132-142 (1990)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值