sunday、kmp、 bm、 horspool字符串匹配算法 code

sunday、kmp 从匹配串的左边往右处理

 bm、 horspool 从匹配串的右边往左处理


一般是某位字符失配时, 主串指针后移一位,继续处理;各个算法核心就是确定主串指针后移长度,移动的次数越少、长度越长就能越快

匹配出结果


规定:主串txt,匹配串pat,要在txt中寻找与pat匹配的字符串;失配时,主串失配字符Tc,位置Ta,匹配串失配字符Pc,位置Pa,

            位置均从0开始,位置值为-1表示相应的字符(串)不存在, pat的长度strlen(pat);

sunday:根据紧跟在pat之后的txt中的字符在pat中的位置addr确定移动距离, 

                 主串指针 移动距离等于strlen(pat) - addr

kmp:根据pat中Pa左侧已匹配的字符串的最长前缀prefix来确定pat指针的移动位置

            pat指针的移动位置是prefix的下一个位置

bm:Tc在pat中距pat末尾最近的距离为len1,pat中Pa右侧已匹配的字符串的好前缀的位置为addr,

          则坏字符badlen = len1, 好前缀goodlen = strlen(pat) - 1 - addr + strlen(pat) - 1 - Pa,

 主串指针移动距离等于 badlen和goodlen中较大的那个

horspool:跟据Tc在pat中Pa左侧最近的出现位置addr确定移动距离,

                      主串指针 移动距离等于Pa- addr


标准KMP:

    KMP:给出两个字符串A(称为主串)和B(称为模板串),长度分别为lenA和lenB,要求在线性时间内,对于每个A[i](0<=i<lenA),求出A[i]往前和B匹配        的最大匹配长度,记为ex[i](或者说,ex[i]为满足A[i-z+1..i]==B[0..z-1]的最大的z值)。KMP的主要目的是求B是不是A的子串,以及若是,B在       A      中所有出现的位置(当ex[i]=lenB时)。
  【算法】
      设next[i]为满足B[i-z+1..i]==B[0..z-1]的最大的z值(也就是B的自身匹配)。设目前next[0..lenB-1]与ex[0..i-1]均已求出,要用它们来求ex[i]的值。


扩展KMP:扩展kmp是求模式串和主串的每一个后缀的最长公共前缀

    给出主A串和模板串B,长度分别为lenA和lenB,要求在线性时间内,对于每个A[i](0<=i<lenA),求出A[i..lenA-1]与B的最长公共前缀长度,记为ex[i](或者说,ex[i]     为满足A[i..i+z-1]==B[0..z-1]的最大的z值)。扩展KMP可以用来解决很多字符串问题,如求一个字符串的最长回文子串和最长重复子串。
  【算法】
      设next[i]为满足B[i..i+z-1]==B[0..z-1]的最大的z值(也就是B的自身匹配)。设目前next[0..lenB-1]与ex[0..i-1]均已求出,要用它们来求ex[i]的值。


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


// 暴力搜索
int StrSearch(const char *str, const char *pat)  
{  
    int i = 0, j = 0, len1, len2;
	if (!str || !pat)
		return -1;
		
	len1 = strlen(str);
	len2 = strlen(pat);
	if (len2 <= 0)
		return -1;
		
    while(i < len1 && j < len2) {  
        if(str[i] == pat[j]) {  
            ++i;      
            ++j;             
        }  
        else  {  
            i = i - j + 1;
            j = 0;  
        }  
    }  
    if(j >= len2)  
        return i - len2;  
    return -1;  
}  

// Sunday字符串匹配算法
int SundayStrSearch(const char *str, const char *pat)  
{  
    int i, j, len1, len2, *next;
	
	if (!str || !pat)
		return -1;
	
	len1 = strlen(str);  
    len2 = strlen(pat);
	if (len2 <= 0)
		return -1;
		
    next = (int *)malloc(256 * sizeof(int));
	if (!next)
		return -1;
		
    for (i = 0; i < 256; i++)  
        next[i] = len2 + 1;  
    for (i = 0; i < len2; i++)  
        next[(unsigned char)pat[i]] = len2 - i; // 记录字符到最右段的最短距离 + 1  
   
	i = 0, j = 0;
	while (i < len1 && j < len2) {
		if (str[i] == pat[j]) {
			i++;
			j++;
		}
		else {
			int tmp = i + len2 - j;
			if (tmp >= len1) {
				i = len1;
				break;
			}
			
			i = i - j + next[(unsigned char)str[tmp]];
			j = 0;
		}
	}
	
	free(next);
	if (j >= len2)
		return i - len2;
	return -1;  
}

// 失配时,pat的下一跳位置(pat = "abab"; value[] = {-1, 0, -1, 0};)
int *Next(char const* pat, int len)    
{    
	int i = 0, j = -1;
    int *value = (int *)malloc(len * sizeof(int));
	if (!value)
		return NULL;

	value[0] = -1;
	while (i < len - 1) {
		if (j == -1 || pat[i] == pat[j]) {
			i++;
			j++;
			value[i] = pat[i] == pat[j] ? value[j] : j;
		}
		else
			j = value[j];
	} 
	
	return value;
}      
  
// Kmp字符串匹配
int KmpStrSearch(const char *str, const char *pat)    
{    
	int len1;
    int len2;
    int *next, i, j;
	
	if (!str || !pat)
		return -1;
    
	len1 = strlen(str);
    len2 = strlen(pat);
	
	if (len2 <= 0)
		return -1;
    next = Next(pat, len2);
	if (!next)
		return -1;
	
    i = 0, j = 0;	
    while(i < len1 && j < len2) {
        if(j == -1 || str[i] == pat[j]) {
            i++;
            j++;
        }
        else {
            j = next[j];
        }
    }
	
	free(next);
	
    if(j >= len2)
        return i - j;

    return -1;    
}  



// 坏字符数组: 某一坏字符距离末尾的长度; 出现多次的字符以最靠右的为准  
int *BadArray(const unsigned char *pat)  
{  
	int len;
	int *bad;
	
	if (!pat)
		return NULL;
	bad = (int *)malloc(256 * sizeof(int));
	if (!bad)
		return NULL;
		
	len = strlen((const char *)pat);
    for (int i = 0; i < 256; i++)
        bad[i] = len;
 
    for (int i = 0; i < len; i++)  
        bad[pat[i]] = len - 1 - i;
		
	return bad;
}  


// 好后缀数组构造  
int *GoodArray(const char *pat)  
{     
	int len, *good;
	char endc;
	const char *cut, *prev, *next, *tmp;
	
	if (!pat)
		return NULL;
	
	len = strlen(pat);
	if (len <= 0)
		return NULL;
		
	good = (int *)malloc(len *sizeof(int));
	if (!good)
		return NULL;
		
    good[len - 1] = 1;   // 好后缀数组的最后元素值为1 
    endc = pat[len - 1]; // 结尾字符  
  
    cut = pat + len - 2;
    for(int i = len - 2; i >= 0; i--, cut--) {
        tmp = pat + len - 2;   
		
        while (1) {  
			int matchflag = 1;
            while (tmp >= pat && *tmp != endc)
				tmp--;  
            prev = tmp;
			tmp = tmp >= pat ? tmp - 1 : tmp;
            next = pat + len - 1;
			
// 分三种情况:      
// case1:找不到匹配的好后缀(完全或部分匹配)
//    pat = "abcd"; cut = 1; 末尾的"d"无匹配字符 
// case2:找到完全匹配的好后缀   
//    pat = "abab"; cut = 1; 末尾的"ab"与开头的"ab"完全匹配     
// case3:找到部分匹配的好后缀   
//    pat = "abba"; cut = 1; 末尾的"a"与开头的"a"部分匹配(完全匹配应该是"ba") 
                    
            if(prev < pat) // case1,无匹配字符;case3,部分匹配(循环回来到此)
                break;  
  
            while(prev > pat && next > cut + 1) { 
				prev--, next--;
                if(*prev != *next) {     
                    matchflag = 0;
                    break;    
                }  
            }  
          
            if(!matchflag) // 未完全匹配,继续往前找 
                continue;
			
			// case2,完全匹配
            if( prev <= pat || *(prev - 1) != *(next - 1))
                break;  
     
        }  
        good[i] = len - 1 - i + next - prev;  
    }  
	
	return good;
} 

// Bm字符串匹配算法
int BmStrSearch(const char *str, const char *pat)  
{  
	int i, j, len1, len2, *bad, *good;
    if (!str || !pat)  
        return - 1;
		
	bad = BadArray((const unsigned char *)pat);
	if (!bad)
		return -1;
	good = GoodArray(pat);
	if (!good) {
		free(bad);
		return -1;
	}
		
	len1 = strlen(str);
	len2 = strlen(pat);
	if (len2 <= 0)
		return -1;
	
    i = len2 - 1;
	j = i;
    while (i < len1 && j >= 0) {  
		int goodskip, badskip;
		if (str[i] == pat[j]) {
			i--;
			j--;
		}
		else {
			badskip = bad[(unsigned char)str[i]];
			goodskip = good[j];
			i += (goodskip > badskip ? goodskip : badskip);
			j = len2 - 1;
		}
    }

	free(bad);
	free(good);
	if (i < len1)
		return i + 1;
    return -1;  
} 


// Horspool字符串匹配算法
int HorspoolStrSearch(const char *str, const char *pat)  
{  
    int  len1, len2, i, j;

	if (!str || !pat)
		return -1;
		
	len1 = strlen(str);
	len2 = strlen(pat);
	if (len2 <= 0)
		return -1;
		
	i = len2 - 1;
	j = i;  
    while (i < len1 && j >= 0) {  
        if (str[i] == pat[j]) {  
            i--;  
            j--;  
        }  
        else {
			// pat串中找到失配字符str[i],计算主串指针移动距离
			while (j >= 0 && pat[j] != str[i])
				j--;
			i = i + len2 - 1 - j;
			j = len2 - 1;
			
        }  
    }  
    
	if(i < len1)      
        return i + 1;                  
    return -1;  
} 


int   main(int argc, char **argv)  
{    
	  int ret;
	  ret = StrSearch(argv[1], argv[2]);
	  printf("1: %s\n", (ret >= 0 ? argv[1] + ret : NULL));
	  ret = SundayStrSearch(argv[1], argv[2]);
	  printf("2: %s\n", (ret >= 0 ? argv[1] + ret : NULL));
	  ret = KmpStrSearch(argv[1], argv[2]);
	  printf("3: %s\n", (ret >= 0 ? argv[1] + ret : NULL));
	  ret = BmStrSearch(argv[1], argv[2]);
	  printf("4: %s\n", (ret >= 0 ? argv[1] + ret : NULL));
	  ret = HorspoolStrSearch(argv[1], argv[2]);
	  printf("5: %s\n", (ret >= 0 ? argv[1] + ret : NULL));
	  int *shift;
	  shift = GoodArray(argv[2]);
	  for (int i = 0, len = strlen(argv[2]); i < len; i++)
		printf("%d ", shift[i]);
	  printf("\n");
	  
	  

    return 0;  
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值