Sunday算法是Daniel M.Sunday于1990年提出的一种比BM算法搜索速度更快的算法。其核心思想是:在匹配过程中,模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较,它在发现不匹配时,算法能跳过尽可能多的以进行下一步的匹配,从而提高了匹配效率。
匹配失败,关注参与匹配的匹配串的最后一位的下一位字符(这里假定为C吧)。
然后判断C是否出现在模式串中。
1.不存在:移动步长=模式串长度+1;
2.存在:移动步长=模式串最右端的该字符到末尾的距离。
有点抽象是不是?
看看这个例子
1 0 1 2 3 4 5 2 匹配串 a b a k f j 3 模式串 a k
如上,在1的位置,匹配串和模式串不匹配。我们就来关注参与匹配的匹配串(a b)的最后一位的下一位字符,这里就是位置2的a。判断a在模式串中是否存在,明显看出是存在,属于情况2,这里可以看出来,模式串中最后端的该字符(位置0的a)到末尾的距离是2(模式串的长度 - 该字符所在位置)。所以移动步长就是2了。
移动后:
1 0 1 2 3 4 5 2 匹配串 a b a k f j 3 模式串 a k
然后继续比较。
下面就贴代码了:
public class StringMatcher { public StringMatcher() { } public static void main(String[] args) { String text=new String("abcbczbac"); String pattern=new String("bac"); System.out.println("匹配结果:"+sunday(text,pattern)); // System.out.println("匹配结果:"+sunday(pattern,pattern)); } public static int sunday(String source, String pattern){ char[] s_array=source.toCharArray(); char[] p_array=pattern.toCharArray(); int s_len=source.length(); int p_len=pattern.length(); //指示返回的位置 int location=0; //指向当前的匹配串和模式串位置 int point_s=0; int point_p=0; //指示匹配串的后一个字符 int s_aim=0; int p_aim; boolean MARK_AIM=true; boolean MATCH_IN_PATTERN=false; if(s_len<p_len) return -1; while(point_p<p_len&&point_s<s_len){ //首次 或者 出现字符串不匹配时这两种情况时候进入, //用于记录参与匹配的后一个位置,和使指向模式串的位置置为0 if(MARK_AIM){ point_p=0; s_aim=point_s+p_len; MARK_AIM=false; } if(s_array[point_s]!=p_array[point_p]) { if(s_aim>s_len) break; p_aim=p_len-1; while(p_aim>=0){ if(p_array[p_aim]==s_array[s_aim]) { MATCH_IN_PATTERN=true; break; } p_aim--; } if(MATCH_IN_PATTERN) //情况二 point_s=location+p_len-p_aim; else //情况一 point_s=location+p_len+1; System.out.println("当期Location:"+location+"; 跳跃到:"+point_s); //记录跳跃后的位置 location=point_s; MATCH_IN_PATTERN=false; MARK_AIM=true; continue; } point_s++; point_p++;
//这个continue很重要,为什么要continue?
//原因在于, point_s++和point_p++后,可能出现越界,所以要再次回到while循环上比较 continue; } if(point_p==p_len) return location; return -1; }//end sunday }
输出:
当期Location:0; 跳跃到:3 当期Location:3; 跳跃到:6 匹配结果:6