串匹配问题-BF算法、KMP算法、BM算法


BF算法

int BF(char A[], char B[]){
    int i = 0, j = 0;
    while(A[i] != '\0' && B[j] != '\0'){
        if(A[i] == B[j]){
            i++;
            j++;
        }else{
            i = i - j + 1;
            j = 0;
        }
    }

    if(B[j] == '\0'){
        return i - j + 1;
    }else{
        return -1;
    }
}

KMP算法:

int KMP(char A[], char B[]){
    int i = 0, j = 0;
    int next[80];
    GetNext1(B, next);
    while(A[i] != '\0' && B[j] != '\0'){
        if(A[i] == B[j]){
            i++;
            j++;
        }else{
            j = next[j];
            if(j == -1){
                i++;
                j++;
            }

        }
    }
    if(B[j] != '\0'){
        return -1;
    }else{
        return (i - j + 1);
    }


}

KMP算法获取next[]值得两种方法:

    方法一:

void GetNext(char B[], int next[]){
    int i , j, len;
    next[0] = -1;
    for(i = 1; B[i] != '\0'; i++){ //依次求next[i]
        for(len = i - 1; len > 0; len--){//len:相等时的前缀的最大长度为i-1,不满足相等时就依次减小 直到找到最大长度 即为next【j】
            for(j = 0; j < len; j++){ //比较B的前缀和后缀是否相等
                if(B[j] != B[i - len + j])
                    break;
            }
            if(j == len){//上步for循环跳出后,表示j走到了最大相等前缀的下一位,也等于前缀的长度
                next[i] = len ;
                break;
            }
        }
        if(len < 1){//前缀的最大长度为0 时
            next[i] = 0;
        }
    }


}

      方法二:

void GetNext1( char B[], int next[]){
    int j = 0, k = -1;
    next[0] = -1;

    while(B[j] != '\0'){
        if(k == -1){ //无相等子串
            j++;
            next[j] = 0;
        }else if(B[j] == B[k]){
            next[++j] = k + 1;

        }else{
            k = next[k];

        }
    }
}

BM算法:

int BMSearch(char *buf, int blen, char *ptrn, int plen, int *skip, int *shift)
{
    int b_idx = plen;
    if (plen == 0)
        return 1;
    while (b_idx <= blen)//计算字符串是否匹配到了尽头
    {
        int p_idx = plen, skip_stride, shift_stride;
        while (buf[--b_idx] == ptrn[--p_idx])//开始匹配
        {
            if (b_idx < 0)
                return 0;
            if (p_idx == 0)
            {
                return b_idx;  //匹配到
            }
        }
        skip_stride = skip[(unsigned char)buf[b_idx]];//根据坏字符规则计算跳跃的距离
        shift_stride = shift[p_idx];//根据好后缀规则计算跳跃的距离
        b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride;//取大者
    }
    return 0;
}

BM算法获取坏字符表:

int* MakeSkip(char *btrn, int bLen)
{
    int i;
    //为建立坏字符表,申请256个int的空间
    //PS:之所以要申请256个,是因为一个字符是8位,
    // 所以字符可能有2的8次方即256种不同情况
    int *skip = (int*)malloc(256*sizeof(int)); //头指针

    if(skip == NULL)
    {
        printf("Error");
        return 0;
    }

    //初始化坏字符表,256个单元全部初始化为pLen
    for(i = 0; i < 256; i++)
    {
        *(skip+i) = bLen;
    }

    //给表中需要赋值的单元赋值,不在模式串中出现的字符就不用再赋值了
   //赋值,从左到右遍历btrn,这样如果一个字符出现两次,后面的覆盖前面的,
    //不在模式中出现的字符不用再赋值,它们使用默认值bLen。
    while(bLen != 0)
    {
        *(skip+(int)*btrn++) = bLen--;
    }

    return skip;
}

BM算法获取好后缀表:

int* MakeShift(char* btrn,int bLen)
{
    //为好后缀表申请pLen个int的空间
    //这样,第一个位置放置长度为1的后缀
    int *shift = (int*)malloc(bLen*sizeof(int));
    int *sptr = shift + bLen - 1;//方便给好后缀表进行赋值的指标
    char *pptr = btrn + bLen - 1;//记录好后缀表边界位置的指标
    char c;

    if(shift == NULL)
    {
        printf("Error");
        return 0;
    }

    c = *(btrn + bLen - 1);//保存模式串中最后一个字符,因为要反复用到它

    *sptr = 1;//以最后一个字符为边界时,确定移动1的距离(因为要与坏字符规则比较,所以这个是个假设,1也是最小的移动距离)

    pptr--;//边界移动到倒数第二个字符

    while(sptr-- != shift)//该最外层循环完成给好后缀表中每一个单元进行赋值的工作
    {
        char *p1 = btrn + bLen - 2, *p2,*p3;

        //该do...while循环完成以当前pptr所指的字符为边界时,要移动的距离
        do{
            while(p1 >= btrn && *p1-- != c);//该空循环,寻找与最后一个字符c匹配的字符所指向的位置

            p2 = btrn + bLen - 2;
            p3 = p1;

            while(p3 >= btrn && *p3-- == *p2-- && p2 >= pptr);//该空循环,判断在边界内字符匹配到了什么位置

        }while(p3 >= btrn && p2 >= pptr);

        *sptr = shift + bLen - sptr + p2 - p3;//保存好后缀表中,以pptr所在字符为边界时,要移动的位置

        pptr--;//边界继续向前移动
    }

    return shift;
}

主函数:

int main()
{

    char A[] = "abcdesdeacd";
    char B[] = "acd";
    int k = BF(A, B);
    printf("%d\n", k);

    k = KMP(A, B);
     printf("%d\n", k);

    char *T = "abcdesdeacd";
    char *P = "acd";
    int *skip = NULL;
    int *shift = NULL;
    skip = MakeSkip(P, strlen(P));
    shift = MakeShift(P, strlen(P));


    printf("%d\n", BMSearch(T, strlen(T), P, strlen(P), skip, shift) + 1);
    return 0;
}

测试结果:

《串匹配问题-BF算法、KMP算法、BM算法》

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/qq_39493274/article/details/80547152
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞