BM算法的C/C++代码实现

关键

  BM算法是高效的字符串匹配算法,比KMP算法效率还高,全称为Boyer-Moore算法。
算法的基本原理可以看:阮一峰的博客:字符串匹配的Boyer-Moore算法BM算法代码深入剖析,里面讲解得很详细。
使用代码实现该算法有两个关键点:

  • 坏字符规则:模式串(短串)从后往前匹配到的第一个不符的字符称为坏字符。这时候只要找到当前坏字符在模式串上一次出现位置,就可:后移位数 = 坏字符的位置 - 搜索词中的上一次出现位置。得到匹配串(长串)的移动位数。
  • 好后缀规则:从后往前匹配的相等子串即为好后缀。同样的,后移位数 = 好后缀的位置 - 搜索词中的上一次出现位置
  • 根据坏字符规则和好后缀规则中的较大者作为移动位数。

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace std;



#define ASIZE 256 //ASCII字母的种类

//1.坏后缀数组建立,类似于字典(map),用于判断坏字符在pattern中的位置
void generateBC(string str, int bc[])
{
	for (int i = 0; i < ASIZE; i++)
	{
		bc[i] = -1;
	}

	for (int i = 0; i < str.size(); i++)
	{
		bc[str[i]] = i;
	}
}

//2.好后缀数组的建立,suffix为后缀字符对应前面的位置,prefix存储:是否存在匹配的前缀字串
void generateGS(string str, int suffix[], bool prefix[])
{
	int n = str.size();
	for (int i = 0; i < n - 1; i++)
	{
		suffix[i] = -1;
		prefix[i] = false;
	}

	for (int i = 0; i < n - 1; i++)
	{
		int j = i;//从第一个字符开始遍历,str[j]
		int k = 0;//最后一个字符的变化,对应下面的str[n - 1 - k]
		while (j >= 0 && str[j] == str[n - 1 - k])//和最后一个字符对比,相等则倒数第二个
		{
			j--;
			k++;
			suffix[k] = j + 1;//如果k=1,则是一个字符长度的后缀对应匹配位置的值
		}
		if (j == -1)//说明有前缀字符对应
			prefix[k] = true;
	}

}

//3.返回好后缀移动的次数,index为坏字符位置-其后面就是好后缀,size为str大小
int getGsMove(int suffix[], bool prefix[], int index, int size)
{
	int len = size - index - 1;//好字符的长度,因为index为坏字符位置,所以要多减1
	if (suffix[len] != -1)//当前len长度的后缀坏字符串前边有匹配的字符
	{
		return index + 1 - suffix[len];//后移位数 = 好后缀的位置(index + 1) - 搜索词中的上一次出现位置
	}

	//index为坏字符,index+1为好后缀,index+2为子好后缀
	for (int i = index + 2; i < size; i++)
	{
		if (prefix[size - i])//因为prefix从1开始
			return i;//移动当前位置离前缀位置,acba-对应a移动3
	}

	return 0;

}




//4.返回找到匹配字符串的头,否则返回-1
int BM(string str, string pattern)
{
	int n = str.size();
	int m = pattern.size();
	int bc[ASIZE];//坏字符数组
	int* suffix = (int *)malloc(sizeof(int) * m);
	bool* prefix = (bool *)malloc(sizeof(bool) * m);;

	generateBC(pattern, bc);
	generateGS(pattern, suffix, prefix);

	int i = 0;
	while (i <= n - m)
	{
		int j = 0;
		for (j = m - 1; j >= 0; j--)
		{
			if (pattern[j] != str[i + j])//从后往前匹配str和pattern
				break;
		}
		if (j < 0)//匹配结束
			return i;
		else     
		{
			int numBc = j - bc[str[i + j]];//bc移动的位数
			int numGs = 0;
			if (j < m - 1)//最后一个字符就是坏字符,无需判断好字符
			{
				numGs = getGsMove(suffix, prefix, j, m);//Gs移动的位数
			}
			i += numBc > numGs ? numBc : numGs;
		}
	}


	return -1;
}



int main()
{
	cout << BM("HERE IS A SIMPLE EXAMPLE", "MPLE") << endl;

}
  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗夜无风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值