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

算法原理这里不废话,网上找到的算法很多再临界情况的处理都有错误,所以自己重写了一个。

预处理创建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__


你可能感兴趣的:(算法,IBM,File,null,search,存储)