BM字符串匹配算法的java实现

BM字符串匹配算法的java实现

为了方便自己下次查找,以博文形式记录


本文只提供BM字符串匹配算法的java实现,其原理请看其他文章,CSDN里有讲得很好的


/**
* 函数建立一张坏字符表
* pstr: 模式串
* @param pstr
*/
public static int[] badCharacterSkip(String pstr) {
int i;
/*PS:之所以要申请256个int空间,是因为一
* 个字符是8位,所以字符可能有2^8=256种不同的情况
* */
int[] skip = new int[256];

//初始化坏字符表,256个单元全部初始化为模式串长度
for(i = 0; i < 256; i++) {
skip[i] = pstr.length();
}

i = pstr.length();
int j = 0;
/**
* 给表中需要赋值的单元赋值,但字符不在模式串pstr中时
* 应该移动pstr.length()个单位,如果字符在pstr中则移动的位置应
* 当是pstr.length()-最右索引index
*/
 
while(i != 0) {
skip[(int)pstr.charAt(j)] = i--;
j++;
}
return skip;
}

/**
* 该函数根据好后缀规则做预处理,建立一张好后缀表
* @param pstr
* @return
*/
public static int[] goodSuffixShift(String pstr) {
//模式串长度plen
int plen = pstr.length();
//好后缀表
int[] shift = new int[plen];
//记录给好后缀表赋值的位置
int sIndex = plen - 1;
//记录好后缀表边界的位置
int pIndex = plen - 1;
char c;

//保存模式串中最后一个字符,因为要反复用到它
c = pstr.charAt(plen - 1);
//以最后一个字符为边界时,确定移动距离为1
shift[plen - 1] = 1;


pIndex--;

//给shift表的每一个单元赋值
while(sIndex-- != 0) {
int p1 = plen - 2, p2, p3;
//该do...while循环完成以pIndex索引为边界时要移动的距离
do {
//该空循环,寻找与最后一个字符c匹配的字符的位置
while(p1 >= 0 && pstr.charAt(p1--) != c);
p2 = plen - 2;
p3 = p1;
//该空循环判断在边界内字符匹配到了什么位置
while(p3 >= 0 && pstr.charAt(p3--) == pstr.charAt(p2--) && p2 >= pIndex);

}while(p3 >= 0 && p2 >= pIndex);
//保存好好后缀表中,以pIndex为边界时,要移动的位置
shift[sIndex] = plen - sIndex + p2 - p3;
//边界继续向前移动
pIndex --;
}

return shift;
}

/**
* buf:文本串
* pstr: 模式串
* @param buf
* @param pstr
* @return
*/
public static boolean BMSearch(String buf, String pstr) {
int[] skip = badCharacterSkip(pstr);
int[] shift = goodSuffixShift(pstr);
int plen = pstr.length();
int blen = buf.length();
int b_idx = plen;
if(plen == 0) 
return true;
//如果文本串没到达尽头
while(b_idx <= blen) {
int p_idx = plen, skip_stride, shift_stride;
//开始匹配
while(buf.charAt(--b_idx) == pstr.charAt(--p_idx)) {
if(b_idx < 0)
return false;
if(p_idx == 0) {
return true;
}
}
//根据坏字符规则计算跳跃的距离
skip_stride = skip[(int)buf.charAt(b_idx)];
//根据好后缀规则计算跳跃的距离
shift_stride = shift[p_idx];
//取大者
b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride;
}

return false;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法BM算法是两种常用的字符串匹配算法。 KMP算法的思想是,当出现不匹配时,已经匹配过的前缀中一定有一部分是可以直接跳过的,不需要重新匹配。通过预处理模式串,得到一个next数组,用于记录模式串中每个前缀的最长可匹配前缀长度。在匹配时,当文本串中出现不匹配字符时,根据next数组可以直接跳过一部分已经匹配过的前缀,从而提高匹配效率。 KMP算法JAVA代码实现如下: ```java public class KMP { public static int kmp(String text, String pattern) { int[] next = getNext(pattern); int i = 0, j = 0; while (i < text.length() && j < pattern.length()) { if (j == -1 || text.charAt(i) == pattern.charAt(j)) { i++; j++; } else { j = next[j]; } } if (j == pattern.length()) { return i - j; } else { return -1; } } private static int[] getNext(String pattern) { int[] next = new int[pattern.length()]; next[0] = -1; int i = 0, j = -1; while (i < pattern.length() - 1) { if (j == -1 || pattern.charAt(i) == pattern.charAt(j)) { i++; j++; next[i] = j; } else { j = next[j]; } } return next; } } ``` BM算法的思想是,在匹配过程中尽可能地多跳过一些字符,从而提高匹配效率。它的核心是两个规则:坏字符规则和好后缀规则。坏字符规则用于处理文本串和模式串不匹配的情况,好后缀规则用于处理文本串和模式串匹配的情况。 BM算法JAVA代码实现如下: ```java public class BM { public static int bm(String text, String pattern) { int[] bc = generateBC(pattern); int[] suffix = new int[pattern.length()]; boolean[] prefix = new boolean[pattern.length()]; generateGS(pattern, suffix, prefix); int i = 0, j = 0; while (i <= text.length() - pattern.length() + j) { for (j = pattern.length() - 1; j >= 0; j--) { if (text.charAt(i + j) != pattern.charAt(j)) { break; } } if (j < 0) { return i; } int x = j - bc[(int) text.charAt(i + j)]; int y = 0; if (j < pattern.length() - 1) { y = moveByGS(j, pattern.length(), suffix, prefix); } i = i + Math.max(x, y); } return -1; } private static int[] generateBC(String pattern) { int[] bc = new int[256]; for (int i = 0; i < 256; i++) { bc[i] = -1; } for (int i = 0; i < pattern.length(); i++) { int ascii = (int) pattern.charAt(i); bc[ascii] = i; } return bc; } private static void generateGS(String pattern, int[] suffix, boolean[] prefix) { int len = pattern.length(); for (int i = 0; i < len; i++) { suffix[i] = -1; prefix[i] = false; } for (int i = 0; i < len - 1; i++) { int j = i; int k = 0; while (j >= 0 && pattern.charAt(j) == pattern.charAt(len - 1 - k)) { j--; k++; suffix[k] = j + 1; } if (j == -1) { prefix[k] = true; } } } private static int moveByGS(int j, int len, int[] suffix, boolean[] prefix) { int k = len - 1 - j; if (suffix[k] != -1) { return j - suffix[k] + 1; } for (int r = j + 2; r <= len - 1; r++) { if (prefix[len - r]) { return r; } } return len; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值