Mortgages Home Cash

Findmortgagehomemortgages A Find Szh Travel United States Zip Code Listings Find Mortgage Home Mortgages KMP快速字符串查找算法 -- 简明现代魔法

Findmortgagehomemortgages A Find Szh Travel United States Zip Code Listings Find Mortgage Home Mortgages

Szh search States United Szh Listings Travel search Listings t Szh tsearchs Listings States daa Szh 6. Find wwsearcha Listings asearche. Szh osearch Travel searchisearchdorDdaa66.comg Findmortgagehomemortgages gewww.aaaqe.como Listings e Find or Code gagsearchs Ls Listings isearchgsearch Listings searchrDdaa66.comv United l Code United United Findmortgagehomemortgages Code Listings Szh searchMsearch Travel search United Travel Travel Szh search Findmortgagehomemortgages Travel Find

0 1 2 3 4 5 6
a b a b a b c
 a b a b c
 ^

然后继续匹配就成功啦。

所以,KMP算法的核心是,如何为目标字符串的每个位置的找到一个k值,组成一个数组F,好在每次匹配到目标字符串的m失配的时候,将目标字符串回溯到F[m],然后继续进行匹配。找到这个数组之后,KMP搜索就算是完成80%了。

下面是构建这个数组F的方法。

这时候目标字符串身兼源字符串和目标字符串两个角色。构建数组T可以说是一个步进的过程,需要用到之前的结果。首先是F[0],F[0]的意思是第一个字符就不匹配,也就是说对源字符串一无所知,这时候没得搞了,直接要源字符串向前挪动一个。在F里,我们使用-1来标记第一个字符就匹配失败的情况。也就是F[0]=-1。F[1]其实肯定是0。我们真正需要计算的是从F[2]到最后的。下面是>=2的时候的计算方法。注意,F[i]代表S的第i个字符匹配"失败"的时候,T需要回溯到的索引的值。如何求F[i]的值呢?首先取得F[i-1]的值,然后看S[i-1]是否=T[F[i-1]],如果等于,那么F[i]=F[i-1]+1。这个原理是递归的。F[i-1]的值是在i-1失配的时候,T索引回溯到的值,如果这时候,这个值与S[i-1]相等,那就说明F[i]可以在F[i-1]的基础上增加1了。否则继续检查S[i-1]是否等于T[[F[i-1]]],直到没有的搜索了,就是0。下面是具体的代码:

/**
 * each value of array rollback means: when source[i] mismatch pattern[i],
 * KMP will restart match process form rollback[j] of pattern with
 * source[i]. And if rollback[i] == -1, it means the current source[i] will
 * never match pattern. then i should be added by 1 and j should be set to
 * 0, which means restart match process from source[i+1] with pattern from
 * pattern[0].
 * 
 * @param pattern
 * @return
 */
 private static int[] getRollbackArray(char[] pattern) {}
 rollback[0] = -1;
 for (int i = 1; i < rollback.length; i++) {} else {}
 }
 }
 return rollback;
 }

上面并没有吧F[1]=1写成固定的,不过根据计算,F[1]始终是=0的。有了这个rollback数组,KMP搜索就是水到渠成了:

/**
 * search pattern chars in source chars.
 * 
 * @param source
 * @param pattern
 * @return
 */
 public static int searchKMP(char[] source, char[] pattern) {}

 // get the rollback array.
 int[] rollback = getRollbackArray(pattern);

 // incremental index of pattern. pointing the char to compare with.
 int currMatch = 0;
 int len = pattern.length;
 // i point the char to compare with
 for (int i = 0; i < source.length;) {}
 } else {}
 }
 return -1;
 }

下面是几个测试方法:

 @Test
 public void testRollBackArray() {};
 int[] rollback = getRollbackArray("PARTICIPATE IN PARACHUTE"
 .toCharArray());
 Assert.assertArrayEquals("Rollback array compare failed to match!",
 expectedRollback, rollback);
 }

 @Test
 public void testKMPSearchMatch() {}

 @Test
 public void testKMPSearchNoMatch() {}

把这三段代码放在一个类里,KMP搜索就算是完事儿了。

在自己看KMP算法之前,很多文章都说神马KMP有代价,只适合目标字符串很长很长,搜索字符串也很长很长的case。但是就我看下来,KMP对于日常一般的搜索也是有优势的。首先,构建rollback数组计算并不复杂,当然需要一个额外的数组空间。但是对于匹配来说,还是有很大的加速优势的,而且目标字符串不需要回溯。所以KMP唯一的代价就是需要一个额外的数组,实际占用的内存应该是目标字符串的两倍(String是char的数组,char=short,int是char的两倍)。难道,真的是为了节省内存所以不采用KMP搜索?

随机文章推荐
网站分类


注:如需转载本文,请注明出处(原文链接),谢谢。更多精彩内容,请进入简明现代魔法首页。

进入新博客
你也许还会对以下文章感兴趣