串的操作(一) BruteForce (BF)算法 朴素的模式匹配

来源:互联网 发布:淘宝模块 编辑:程序博客网 时间:2024/05/17 06:46

这个系列全是一些经典的算法,难度并不高,但十分经典。

 

串的基本操作(一)

 

http://blog.fishc.com/2258.html

让编程改变世界

Change the world by program


字符串

以前的计算机刚被发明的时候,主要作用是做一些科学和工程的计算工作,科学家发明计算机的时候压根儿不可能想到后人还可以用来看毛片。

刚开始的计算机都是处理数值工作,后来引入了字符串的概念,计算机开始可以处理非数值的概念了(当然原理还是用数值来模拟非数值,通过ASCII码表)。

鉴于大家对字符串已经有足够的了解,我们这几节就需要讲点不一样的东西才能满足大家的口味,我们会谈谈“BoyFriend”算法和“看毛片”算法。

我们先来研究下“串”这样的数据结构:

定义:串(String)是由零个或多个字符组成的有限序列,又名叫字符串。

一般记为 s =“a1a2a3……an”(n>=0)

串可以是空串,即没有字符,直接由 ””表示(注意里边没有空格哦~),或者可以用希腊字母Φ来表示(读fai,四声)。

子串与主串,例如“FishC”是“FishC.com”的子串,反之则倒过来。

关于子串和主串,小甲鱼在做课件搜集资料的时候还发觉一些有意思的:“over”是“lover”的子串,“end”是“friend”的子串,“lie”是“believe”的子串。

可见造字者对这世态是看得是清清楚楚明明白白真真切切!

相比起来中国的汉字比较有内涵,例如讲男女同睡在一张床上,我们可以仅仅只用“非、羽、臼、日”四个字来概括。

自己发挥想象力哈~

字符串的比较

字符串比较大小跟传统的数字比较有点差别,很容易我们可以知道2比1要大,可要是“FishC”和“fishc.com”呢?要怎么比较?比长短?比大小?

比大小!没错,比的就是字符串里每个字符的ASCII码大小,因为‘F’== 70 ‘f’== 102,‘f’>‘F’,所以“fishc.com”>“FishC”

其实这样的比较大小没有多大意义,字符串的比较我们更重视是否相等!

字符串的存储结构

字符串的存储结构与线性表相同,也分顺序存储结构和链式存储结构。

字符串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。

按照预定义的大小,为每个定义的字符串变量分配一个固定长度的存储区,一般用定长数组来定义。

与线性表相似,既然是固定长度的存储区,就存在一个空间分配不灵活的问题,那么会考虑用链式存储结构。

不同的是字符串我们一般都是连在一起表述的,“断章取义”的情况并不多,所以习惯上我们通常还是会直接定义一个足够长度的存储区来存储的。

 

 

BF算法

事实上,BF算法并不是“BoyFriend”算法的意思,他有一个很黄很暴力的原名:Brute Force

BF算法属于朴素的模式匹配算法,它的核心思想是:

有两个字符串S和T,长度为N和M。首先S[1]和T[1]比较,若相等,则再比较S[2]和T[2],一直到T[M]为止;若S[1]和T[1]不等,则T向右移动一个字符的位置,再依次进行比较。

该算法最坏情况下要进行M*(N-M+1)次比较,时间复杂度为O(M*N)。

在这里S是主串,T是子串,这种子串的定位操作通常称作串的模式匹配。

假设我们要从主串S=“IloveFishC.com”找到T=“FishC”这个子串的位置,按照BF算法,我们需要进行下边的步骤:

课后作业:

用你熟悉的一门语言写出BF算法的实现形式,参考答案详见课件与源代码。

考虑为什么BF算法很黄很暴力,但效率低下?

int len1;int len2;void BruteForce(char* src,char* des,int i,int j) { if(len1-i>0) { if(src[i]!=des[j]) { j=0; i++; BruteForce(src,des,i,j); } else { if(j==len2-1) { printf("匹配到了%c\n",src[i-len2+1]); return; } i++; j++; BruteForce(src,des,i,j); } } else { printf("不匹配\n"); return; } }#include <string.h>int _tmain(int argc, _TCHAR* argv[]){char* str1="IloveFishC.comt";char* str2="FishC.com";len1=strlen(str1);len2=strlen(str2);BruteForce(str1,str2,0,0);return 0;}

 

下面是小甲鱼提供的代码:

// 返回子串T在主串S中第pos个字符之后的位置// 若不存在,则返回0// T非空,1 <= pos <= strlen(S)// 注意:我们这里为了表述方便,字符串使用了第一个元素表示长度的方式。int index( String S, String T, int pos ){ int i = pos; // i用于主串S中当前位置下标 int j = 1;  // j用于子串T中当前位置下标  while( i <= S[0] && j <= T[0] ) // i或j其中一个到达尾部即终止搜索! {  if( S[i] == T[i] ) // 若相等则继续下一个元素匹配  {   i++;   j++;  }  else    // 若失配则j回溯到第一个元素从新匹配  {   i = i-j+2;  // i回溯到上次匹配首位的下一个元素,这是效率低下的关键!   j = 1;  } }  if( j > T[0] ) {  return i - T[0]; } else {  return 0; }}