您的位置:首页 > 编程语言 > C语言/C++

Boyer-Moore 精确匹配算法实现(C/C++)

2012-03-09 11:40 316 查看
算法原理这里不废话,网上找到的算法很多再临界情况的处理都有错误,所以自己重写了一个。

预处理创建shift资源表时的效率比较一般,但是简单易懂! 如果你有更好的版本希望发来研究研究。

/*
* Boyer-Moore 精确匹配算法
* -------------------------------------------
* copyright (c) 2012 Niu Chenguang <chrisniu1984@gmail.com>
*
* file: bm.h
*/

#ifndef __BM_H__
#define __BM_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BM_SKIP_SIZE    256
#define BM_SHIFT_SIZE   128 // 此值决定字串最大长度

/*
* 为已知字符串创建skip资源表。
*
* @skip: [in/out] 存储skip资源的int数组。元素数必须为BM_SIKP_SIZE个。
* @sub: [in] 已知字符串
* @sub_len: [in] 字符串长度
*
* @RETURN: 0 = 成功,-1 = 失败
*/
static inline int bm_make_skip(int skip[], unsigned char *sub, int sub_len)
{
if (NULL == skip || NULL == sub || sub_len <= 0) {
return -1;
}

memset(skip, 0x00, sizeof(int)*BM_SKIP_SIZE);

int i;
for (i=0; i<BM_SKIP_SIZE; i++) {
skip[i] = sub_len;
}

while (sub_len != 0) {
skip[*sub] = --sub_len;
sub++;
}

return 0;
}

/*
* 为已知字符串创建shift资源表。
*
* @shift: [in/out] 存储shift资源的int数组。元素数必须为BM_SHIFT_SIZE个。
* @sub: [in] 已知字符串
* @sub_len: [in] 字符串长度
*
* @RETURN: 0 = 成功,-1 = 失败
*/
static inline int bm_make_shift(int shift[], unsigned char* sub,int sub_len)
{
if (NULL == shift || NULL == sub ||
sub_len <= 0 || sub_len > BM_SHIFT_SIZE) {
return -1;
}
memset(shift, 0x00, sizeof(int)*BM_SHIFT_SIZE);

int pos;
for (pos = sub_len-1; pos >= 0; pos--) {
//int i=0;
//printf("---------------------\n");
//printf("%s\n", sub);
//for (i=0; i<pos; i++) {
//    printf(" ");
//}
//printf("%s\n", sub+pos);

unsigned char *good = sub + pos + 1; // 好后缀起始位置。
int good_len = sub_len - pos - 1;  // 好后缀长度

// 此循环是为了匹配到尽量长的好后缀串
while (good_len > 0) {

// p 为开始位置查找好后缀
unsigned char *p = sub + sub_len - 1 - good_len;

// 此循环是为了从右向左逐个位置查找好后缀串。
while (p >= sub) {
// 在p位置找到了good
if (memcmp(p, good, good_len) == 0) {
shift[pos] = (sub_len-pos)+(good-p)-1;
break;
}

// 向左移动一个位置,准备继续查找good串
p--;
}

// 此shift位置有值,说明查找成功,直接break
if (shift[pos] != 0) {
break;
}

// 取好后缀的子串
good++;
good_len--;
}

// 此shift位置没有值,说明没有匹配到good串及其字串
if (shift[pos] == 0) {
shift[pos] = sub_len-pos;
}

//for(i=0;i<shift[pos]-(sub_len-pos);i++){
//    printf(" ");
//}
//printf("%s\n", sub);
}

return 0;
}

static inline int bm_search(unsigned char *str, int str_len,
unsigned char *sub, int sub_len,
int skip[], int shift[])
{
if (sub_len == 0) {
return 1;   // 根据实际需要,修改这个返回值。
}

if (sub_len > str_len) {
return 0;
}

int str_end = sub_len - 1;
while (str_end <= str_len) {
int sub_end = sub_len-1;

while (str[str_end] == sub[sub_end]) {
if (sub_end == 0) {
return 1;
}
str_end--;
sub_end--;
}

int skip_stride = skip[str[str_end]];
int shift_stride = shift[sub_end];

str_end += MAX(skip_stride,shift_stride);
}

return 0;
}

#endif // __BM_H__
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: