字符串匹配算法

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

#define ASCII_SIZE 256

/*一个字符一个字符移动比较*/
//暴力匹配BF算法
int BF_BruteForce(char *dest, char *src)
{
    int i, j;
    
    if (NULL == dest || NULL == src)
    {
        return -1;
    }
    
    int n = (int)strlen(dest);
    int m = (int)strlen(src);
    
    if (n > m)
    {
        return -2;
    }
    
    for (i = 0; i <= m - n; i++)
    {
        if (dest[0] == src[i])
        {
            for (j = 0; j <= n; j++)
            {
                if (dest[j] != src[j + i])
                {
                    break;
                }
                else if (dest[j + 1] == '\0')
                {
                    return 1;
                }
            }
        }
    }
    
    return 0;
}
//RK算法:利用哈希表,每个子字符串为一个哈希值,做比较
//BM算法
/*创建坏点哈希表*/
void BM_CreatBadSpotHash(char dest[], int n, int b[])
{
    int i;
    for (i = 0; i < ASCII_SIZE; i++)
    {
        b[i] = -1;
    }
    /* 哈希表存储每个字符最后出现的下标 */
    for (i = 0; i < n; i++)
    {
        int asc = (int)dest[i];
        b[asc] = i;
    }
}

int BM_BoyerMoore_BadSpot(char dest[], int n, char src[], int m)
{
    int i, j;
    int b[ASCII_SIZE];
    BM_CreatBadSpotHash(dest, n, b);
    i = 0;
    while (i < m - n)
    {
        for (j = n - 1; j >= 0; j--)
        {
            if (dest[j] != src[i + j])
            {
                break;
            }
        }
        if (j < 0)
        {
            return i;
        }
        else
        {
            //计算移动的距离
            i = i + (j - b[(int)src[i + j]]);
        }
    }
}

//创建后缀哈希表
//suffix 存储字符串后缀字符在前面最后一次出现的下标, prefix 存储后缀字符串是否有前缀字符串与之相同
void BM_CreatSuffixHash(char dest[], int n, int suffix[], int prefix[])
{
    int i, j;
    int k;
    for (i = 0; i < n; i++)
    {
        suffix[i] = -1;
        prefix[i] = 0;
    }
    //从前往后寻找相同后缀
    for (i = 0; i < n - 1; i++)
    {
        k = 0;
        j = i;
        while ((j >= 0) && (dest[j] == dest[n - k - 1]))
        {
            j--;
            k++;
            suffix[k] = j + 1;
        }
        if (-1 == j)
        {
            prefix[k] = 1;
        }
    }
    
    // for (k = 1; k <= n - 1; k++)
    // {
        // printf("%d, %d\n", suffix[k], prefix[k]);
    // }
}

//根据后缀哈希表移动,j表示坏点的下标,n为子串的长度
int BM_BoyerMoore_GoodSuffix(int j, int n, int suffix[], int prefix[])
{
    int i;
    //计算后缀个数
    int k = n - j - 1;
    if (suffix[k] != -1)
    {
        //加1表示从坏点后移一个,移动到后缀的第一个字母的下标
        return j - suffix[k] + 1;
    }
    else
    {
        //如果没有后缀,则依次看前缀有几个字符能和后缀匹配上
        for (i = j + 2; i < n - 1; i++)
        {
            if (1 == prefix[n - i])//如果后缀的n - i个字符有对应前缀
            {
                return i;
            }
        }
    }
}

int max(int a, int b)
{
    return a > b ? a : b;
}

int BM_BoyerMoore(char a[], int n, char b[], int m)
{
    int i, j;
    int x, y;
    
    int bad_spot_hash[ASCII_SIZE];
    BM_CreatBadSpotHash(a, n, bad_spot_hash);
    int suffix[n];
    int prefix[n];
    BM_CreatSuffixHash(a, n, suffix, prefix);
    i = 0;
    while (i < m - n)
    {
        for (j = n - 1; j >= 0; j--)
        {
            if (a[j] != b[i + j])
            {
                break;
            }
        }
        if (j < 0)
        {
            return i;
        }

        x = (j - bad_spot_hash[(int)b[i + j]]);
        
        y = 0;
        
        if (j < n - 1)
        {
            y = BM_BoyerMoore_GoodSuffix(j, n, suffix, prefix);
        }
        
        i = i + max(x, y);
    }
    
    return -1;
}

#define A_SIZE 4
#define B_SIZE 10
/*
在排序中可以不用坏点排序,直接用后缀,但是用坏点可以提高一定效率
后缀的本质和坏点相同,只不过是按字符串来移动

*/
int main()
{
    char a[A_SIZE] = "baaa";
    char b[B_SIZE] = "baaaaaaaaa";
    printf("%d\n", BM_BoyerMoore(a, A_SIZE, b, B_SIZE));
    //int s[A_SIZE];
    //int p[B_SIZE];
    //BM_CreatSuffixHash(a, A_SIZE, s, p);
    return 0;
}

 

 

参考链接:

https://blog.csdn.net/every__day/article/details/86654361

posted @ 2019-04-04 16:49  小时候挺菜  阅读(222)  评论(0编辑  收藏  举报