Boyer-Moore算法的C++实现

 BM算法-阮一峰的网络日志;

 以上给出了通俗易懂的算法讲解,下面给出代码实现,使用的宽字符,这样就不限于英文字母了:(stdafx.h编译不过去就屏蔽掉)

// StringSearch_BoyerMoore.cpp : 定义控制台应用程序的入口点。
//
/*
	@Date: 2016/03/21 18:31;
	@Where: Tongzhou District of Beijing;
	@Author: Alex Hong;
	@Mail: worksdata@163.com;
	@Reference: 
		http://www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.html BM算法-阮一峰的网络日志;
*/

#include "stdafx.h"
#include <sstream>
#include <iostream> 
#include <string>
#include <vector>
#include <map>
using namespace std;

typedef std::vector<int> TArrayInt;
TArrayInt g_arSearchResult;//store the index of searched result;
typedef std::map<std::wstring, int> TMapWszToInt; //E.g. "我,4":7;
typedef std::map<int, int> TMapIntToInt;


void StringSearch_BM(wchar_t* wszStrMain, int iLenMain, wchar_t* wszSearch, int iLenSearch, bool bOnlyFirst)
{
	//reset variables;
	g_arSearchResult.clear();

	//handle exceptions..
	if( NULL == wszStrMain || NULL == wszSearch)
		return;
	if(iLenSearch > iLenMain)
		return;
	/*
		未知的字符有很多, 但是已知的搜索字符是有限的. 我们只初始化已知的字符的跳跃值(Skip), 数组中不存在的就是-1;
		Shift数组的初始化同样基于这种想法.
		初始化这两个数组的值后, 对于长主串/耗时的任务是有利的;
	*/

	int i = 0, j = 0;

	//Initialize the Skip array data for Bad-Character-Rules..
	TMapWszToInt mapSkip;
	mapSkip.clear();
	TMapWszToInt::iterator it1;
	std::wostringstream oStream;
	for(i = iLenSearch - 1; i > 0; --i)//0-->1;
	{
		for(j = i - 1; j >= 0; --j)
		{
			if(wszSearch[j] != wszSearch[i]) //Skip is for bad character which is different with wszSearch;
			{
				oStream.clear();//clear bad bits;
				oStream.str(L"");//clear data;
				oStream<<wszSearch[j]<<','<<i;//format to key string;
				//wcout<<oStream.str().c_str()<<endl;//test..
				it1 = mapSkip.find(oStream.str());
				if(mapSkip.end() == it1) //only set the pos of nearest same bad character;
					mapSkip.insert(TMapWszToInt::value_type(oStream.str(), i-j));
			}
		}
	}

	//好后缀的前提是: 至少有一个字符是相同的!!!!!!
	//Initialize the Shift array data for Good-Suffix-Rules..
	//Shift数组的键值是好后缀的最左字符的下标;
	//1. 首先判断模式串中是否含有完全一致的好后缀;有就直接计算位移, EXIT;
	//  其实这本身就是一个字符串搜索的过程,为了简化计算, 这里只使用Bad-Character-Rule;
	//2. 如果没有, 就在串首寻找好后缀的子串;
	TMapIntToInt mapShift;	
	mapShift.clear();
	mapShift.insert(TMapIntToInt::value_type(0, iLenSearch));//0==i的话就匹配了, Shift[]=iLenSearch;
	//1. try to find the same suffix..
	for(int iSuffixPosL = iLenSearch - 1; iSuffixPosL > 0; --iSuffixPosL)//iSuffixPosL: left position of good suffix;
	{
		int iSuffixLen = iLenSearch - iSuffixPosL;
		wchar_t* wszSuffix = wszSearch + iSuffixPosL;
		
		for(int iPosMainL = iSuffixPosL - 1; iPosMainL >= 0;)//不断向左移动suffix串比较;
		{
			//compare..
			for(i = 0; i < iSuffixLen; ++i)
			{
				if(wszSearch[iPosMainL+i] != wszSuffix[i])//bad character
					break;
			}
			//check result..
			if(iSuffixLen == i) //find it!
			{				
				mapShift[iLenSearch-i] = iSuffixPosL - iPosMainL; 
				break; //结束为当前suffix找Shift值;
			}
			else //calc the skip distance;
			{
				for(j = i + 1; j < iSuffixLen; ++j)//在suffix中寻找最近的坏字符
				{
					if(wszSuffix[j] == wszSearch[iPosMainL+i])
						break;
				}
				iPosMainL = iPosMainL - (j - i);//iSuffixLen==j的情况也适用;	
			}
		}
	}
	//2. try to find the child suffix at head..
	TMapIntToInt::iterator it2;
	for(int iSuffixPosL = iLenSearch - 1; iSuffixPosL > 0; --iSuffixPosL)//iSuffixPosL: left position of good suffix;
	{
		it2 = mapShift.find(iSuffixPosL);
		if(mapShift.end() == it2)
		{
			wchar_t* wszSuffix = NULL;
			int iSuffixLen  = 0;
			for(i = 0; i < iLenSearch - iSuffixPosL; ++i)//form sub suffix big to small.
			{
				wszSuffix = wszSearch + iSuffixPosL + i;
				iSuffixLen = iLenSearch - iSuffixPosL - i;
				//compare if match..				
				for(j = 0; j < iSuffixLen; ++j)
				{
					if(wszSearch[j] != wszSuffix[j])
						break;
				}
				if(iSuffixLen == j) //find it!
				{
					mapShift[iSuffixPosL] = iLenSearch - iSuffixLen; //以好后缀的最后一个字符为准;
					break;
				}
			}

			//if no sub suffix at all..
			it2 = mapShift.find(iSuffixPosL);
			if(mapShift.end() == it2)
				mapShift[iSuffixPosL] = iLenSearch;
		}
	}

	//================
	//start to search!
	//================
	int iPosMainL = 0;//left iterator of main string;
	//int iPosSearch = 0;//iterator of search string; no use!
	while( iPosMainL <= iLenMain - iLenSearch + 1)
	{
		//compare with aligned sub-string..
		int i = iLenSearch - 1;
		for(; i >= 0; --i)//right to left comparison;
		{
			if(wszSearch[i] != wszStrMain[iPosMainL+i])//bad character!
				break;
		}
		//----calc how many steps to move rightwards..----
		int iSkip = 0;
		if(i < 0)
		{
			g_arSearchResult.push_back(iPosMainL);
			if(bOnlyFirst)
			{
				mapSkip.clear();
				mapShift.clear();
				return;
			}
			iSkip = iLenSearch;
		}
		else
		{
			//1. calc max skip steps for bad characters..
			oStream.clear();//clear bits;
			oStream.str(L"");//clear data;
			oStream<<wszStrMain[iPosMainL+i]<<','<<i;
			it1 = mapSkip.find((wchar_t*)oStream.str().c_str());
			if(mapSkip.end() == it1)
				iSkip = i + 1;
			else
				iSkip = it1->second;
		}
		
		//--2. calc max shift steps for good suffix..--
		int iShift = 0;
		if(i < iLenSearch - 1)//至少有一个相同的字符才可以使用"好后缀"规则!
		{
			it2 = mapShift.find(i-1);
			if(mapShift.end() != it2)
				iShift = it2->second;
		}
		iPosMainL += ((iSkip>iShift) ? iSkip : iShift);
	}

	//clear..
	mapSkip.clear();
	mapShift.clear();
}

int _tmain(int argc, _TCHAR* argv[])
{
	wchar_t wszMainStr[] = L"THIS IS A 我你她我不是的LE EXA我们我们MPLEEXAMPLE我们";
	wchar_t wszSearchStr[] = L"我们";

	StringSearch_BM(wszMainStr, wcslen(wszMainStr), wszSearchStr, wcslen(wszSearchStr), false);

	for(TArrayInt::iterator it = g_arSearchResult.begin(); it != g_arSearchResult.end(); ++it)
		cout<<*it<<endl;

	//clear..
	g_arSearchResult.clear();

	getchar();
	return 0;
}

 一些例子分析过程:

主字符串:       THIS IS A SIMPLE EXAMPLE  (长度:24)
搜索字符串:    EXAMPLE                            (长度:7)

    
mapSkip的初始化值:

主串中的坏字符的下面字符是:'E'

  mapSkip['L,6'] = 1
  mapSkip['P,6'] = 2
  mapSkip['M,6'] = 3
  mapSkip['A,6'] = 4
  mapSkip['X,6'] = 5
                             mapSkip['E,6'] = 不是坏字符, 舍去
  其他: 7
-----------------------------------------------------------
搜索字符串:    EXAMPLE                   (长度:7)
主串中的坏字符的下面字符是:
               'L'
  mapSkip['P,5'] = 1
  mapSkip['M,5'] = 2
  mapSkip['A,5'] = 3
  mapSkip['X,5'] = 4
  mapSkip['E,5'] = 5
  其他:6
---------------------------------------------------------------
...
主字符串:       THIS IS A SIMPLE EXAMPLE  (长度:24)
搜索字符串:    EXAMPLE                           (长度:7)
主串中的坏字符的下面字符是:
               'X'
  mapSkip['E,1'] = 1
  其他:2
---------------------------------------------------------------
 mapSkip['[任何],0'] = 1

============好后缀数组初始化的流程============================

搜索字符串:    SIMPLE EXAMPLE  (长度:14)

0  1  2  3  4  5  6  7  8  9  10  11  12  13
S  I  M  P  L   E     E  X  A   M   P    L    E

好后缀的第一个字符为:'E' --> Shift[13] = 6; //以最后一个字符的下标为基准计算要移动的距离;
好后缀的第一个字符为:'L' --> Shift[12] = 8; //"SIMPLE"中有全匹配的, 取全匹配的;
好后缀的第一个字符为:'P' --> Shift[11] = 8;
好后缀的第一个字符为:'M' --> Shift[10] = 8;
好后缀的第一个字符为:'A' --> Shift[9]  = 14; //没有全匹配的, 在串头部找子串匹配的, 这里没有, 认为在-1位置(不妨虚拟出来);
...
好后缀的第一个字符为:'I' --> Shift[1] = 14;
好后缀的第一个字符为:'S' --> Shift[0] = 14;//可能需要特殊处理;


E.g. 2

0  1  2  3   4   5   6   7
L  E  X  A   M   P   L   E

好后缀的第一个字符为:'E' --> Shift[7] = 6;
好后缀的第一个字符为:'L' --> Shift[6] = 6;
好后缀的第一个字符为:'P' --> Shift[6] = 6;

转载于:https://www.cnblogs.com/tupx/p/5337145.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Boyer-Moore算法是一种在文本中搜索模式的有效算法,它使用一个简单的技巧来提高搜索效率。下面是一段C语言实现Boyer-Moore算法的代码:int BoyerMooreSearch(char *txt, char *pat) { int m = strlen(pat); int n = strlen(txt); int badchar[256]; /* 填充bad character array */ FillBadChar(pat, m, badchar); int s = 0; while (s <= (n - m)) { int j = m-1; /* 找到匹配的字符*/ while (j >= 0 && pat[j] == txt[s+j]) j--; /* 找到匹配的字符 */ if (j < 0) { /* 打印匹配的字符 */ printf("在位置 %d 匹配成功\n", s); s += (s+m < n)? m-badchar[txt[s+m]] : 1; } else s += max(1, j - badchar[txt[s+j]]); } return -1; } ### 回答2: Boyer-Moore算法是一种用于字符串匹配的高效算法,相比于传统的字符串匹配算法,它具有更快的速度和更少的比较次数。下面是在C语言中实现Boyer-Moore算法的代码: ```c #include <stdio.h> #include <string.h> #define MAX_CHAR 256 // 计算字符串中每个字符出现的最后位置 void computeLastOccurence(char *pattern, int *lastOccurence) { int len = strlen(pattern); for(int i = 0; i < MAX_CHAR; i++) { lastOccurence[i] = -1; } for(int i = 0; i < len; i++) { lastOccurence[(int)pattern[i]] = i; } } // 实现Boyer-Moore算法 int boyerMoore(char *text, char *pattern) { int textLen = strlen(text); int patternLen = strlen(pattern); int lastOccurence[MAX_CHAR]; // 计算每个字符在pattern中最后出现的位置 computeLastOccurence(pattern, lastOccurence); int shift = 0; while(shift <= textLen - patternLen) { int j = patternLen - 1; // 从后往前匹配pattern和text while(j >= 0 && pattern[j] == text[shift + j]) { j--; } if(j < 0) { // 匹配成功,返回匹配的起始位置 return shift; } else { // 计算pattern向右移动的距离 int maxShift = j - lastOccurence[(int)text[shift + j]]; if(maxShift < 1) { maxShift = 1; } shift += maxShift; } } return -1; // 未找到匹配的位置 } int main() { char text[] = "ABABCABABDABABCABABCDE"; char pattern[] = "ABABCABABCDE"; int result = boyerMoore(text, pattern); if(result == -1) { printf("未找到匹配的位置\n"); } else { printf("匹配位置: %d\n", result); } return 0; } ``` 以上是Boyer-Moore算法在C语言中的实现代码。该算法通过计算每个字符在模式串中最后出现的位置,从而优化了字符串匹配的效率。在主函数中,我们定义了一个文本串和模式串,并调用boyerMoore函数进行匹配。最终输出匹配的位置或未找到匹配的提示信息。 ### 回答3: 下面是一个使用Boyer-Moore算法的C代码示例: ```c #include <stdio.h> #include <string.h> #define MAX_CHARS 256 // 计算字符串中每个字符最右出现的位置 void calculateBadChar(char *str, int size, int badChar[MAX_CHARS]){ int i; for(i = 0; i < MAX_CHARS; i++){ badChar[i] = -1; } for(i = 0; i < size; i++){ badChar[(int)str[i]] = i; } } // Boyer-Moore算法 int boyerMoore(char *text, char *pattern){ int textSize = strlen(text); int patternSize = strlen(pattern); int badChar[MAX_CHARS]; calculateBadChar(pattern, patternSize, badChar); int shift = 0; while(shift <= (textSize - patternSize)){ int j = patternSize - 1; while(j >= 0 && pattern[j] == text[shift+j]){ j--; } if(j < 0){ return shift; }else{ shift += (j - badChar[(int)text[shift+j]]); } } return -1; } int main(){ char text[] = "ABABDABACDABABCABAB"; char pattern[] = "ABABCABAB"; int result = boyerMoore(text, pattern); if(result == -1){ printf("Pattern not found in the text\n"); }else{ printf("Pattern found at index: %d\n", result); } return 0; } ``` Boyer-Moore算法是一种用于字符串搜索的高效算法,根据Pattern中的字符在Text中的出现位置规律,跳过一些不需要再进行比较的字符,从而提高搜索效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值