4.4 串的操作

4.3.3 串的模式匹配算法


  • 【算法目的】确定主串中所含子串(模式串)第一次出现的位置(定位)
  • 【算法种类】
    • BF算法
    • KMP 算法

BF 算法

Brute-Force简称为BF算法,亦称为简单匹配算法。采用穷举法的思路

例如,设目标串S="aaaaaab",模式串T="aaab"。S的长度为n(n=6),T的长度为m(m=4)。
BF算法的匹配算法如下:

这里是有动画,但是动画不知道怎么上传所以无法显示。这里动画内容就是暴力破解法相关过程。

当匹配成功时,返回结果是i-t.length

Index(S,T,pos)

  • 将主串的第pos个字符和模式串的第一个字符比较

  • 若相等,继续逐个比较后续字符

  • 若不等,从主串的下一个字符起,重新与模式串的第一个字符比较。

    • 直到主串的一个连续子串字符序列与模式串相等。返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。
    • 否则,匹配失败,返回值为0
  • 【算法描述】

    int Index_BF(SString S,SString T){
      	 // 首先是判断主串和子串是否为空
      	 if(S==""||T==""){
           		return ERROR;
         }
    
     	// 创建变量
      	 int i=0,j=0;    // 也就相当于两个指针变量
      	 // 开始循环判断,循环结束的标志就是两个指针其中某一个指针指向空(可以说是指针越界)
      	 while(i<=S.length&&j<=T.length){
           	/*  如果说两个指针的元素相等,将两个指针向后移动一位
           	    如果说两个指针的元素不相等,就进行回溯。
           	*/
           	if(S.ch[i]==T.ch[j]){  // 如果说两者相等的情况下
              	++i;++j;  				// 两个指针向后进行移动
            }else{							  // 否则
              	i=i-j+2;           // i 进行回溯,为啥还需要+2  指针指向的数组的基地址
              										// 而且我们是需要跳过首位元素 所以需要加上2
              	j=1;
            }
           // 这里是结束条件的判断
           	if(j>=T.length){
              	return i-T.length;
            }else{
              	return 0;
            }
         }
    }
    
    // 将这个函数进行重载
    int  Index_BF(SString S,SString T,int pos[]){
      	// 首先是判断主串和子串是否为空
      	 if(S==""||T==""){
           		return ERROR;
         }
      
     		 // 创建变量
      	 int i=pos,j=0;    // 也就相当于两个指针变量
      	 // 开始循环判断,循环结束的标志就是两个指针其中某一个指针指向空(可以说是指针越界)
      	 while(i<=S.length&&j<=T.length){
           	/*  如果说两个指针的元素相等,将两个指针向后移动一位
           			如果说两个指针的元素不相等,就进行回溯。
           	*/
           	if(S.ch[i]==T.ch[j]){
              	++i;++j;
            }else{
              	i=i-j+2;
              	j=1;
            }
           	if(j>=T.length){
              	return i-T.length;
            }else{
              	return 0;
            }
         }
    }
    

若n为主串的长度,m为子串长度,最坏的情况是

  • 主串前面n-m个位置都部分匹配到子串的最后一位,即这n-m位各比较了m次
  • 最后m位也各比较了1次
    总次数为:(n-m)* m+m=(n-m+1)* m
    若m<<n,则算法复杂度为O(n*m)

KMP 算法


该算法较BF算法有较大改进,从而使算法效率有了某种程度的提高

利用已经部分匹配的结果而加快模式串的滑动速度?
且主串S的指针i不必回溯,可将时间复杂度提高到O(n+m)

为此,定义next[j]函数,表明当模式中第j个字符与主串中相应字符"失配"时,在模式中需重新和主串中该字符进行比较的字符位置。

上面的max函数所表达的意思是:前缀和后缀相等的情况下,最长的情况
image

咱们看下面的例子
image

这里是需要说明一下的是:每一位元素对应的next[]数组的值是指该(元素)字符前面的子串的最长前后缀相等的长度值。

如何求next[]

  • 【算法思想】除当前字符外的最长相同前缀后缀。这里主要是先确定那个位置与首位字符相等,然后在此基础进行判断进行累加操作,不相等就将头部指针进行置0

  • 【算法描述】

    void get_next(SString T,int &next[]){
      // 命名两个指针进行初始化
      int j=0,i=-1;
      // 首先是将第一位进行初始化操作。
      next[0]=-1;
      // 进入循环结构
      while(j<T.length){
        // 当i归置-1时或者说当两个指针指向字符相等时,将两个指针向后移动一位,进行累加判别。
        if(i==-1||T.ch[i]==T.ch[j]){
          ++i;++j;
          // 并且将j指针对应的next[]进行赋值。
          next[j]=i
        }else{
         	// 当两个指针指向的元素不相等时,那么这个将执行多次,以至于将i归置-1,但是这个时候j指针是不动的。
          i=next[i];
        }
      }
    }
    

KMP算法

  • 【算法思想】通过上面的next[]数组获得模式串回溯的位置

  • 【算法描述】

    int Index_KMP(SString S,SString T,int pos){
      	//  i指针是指向主串,j指针是指向模式串
      	int i=pos,j=1;
      	while(i<S.length&&j<T.length){
    	      if(j==0||S.ch[i]==T.ch[j]){
            	++i;++j;
     	     }else{
            	j=get_next[j];
      	       }
      	  }
      	if(j>T.length)
          	return i-T.length;
      	else 
          	return 0;
    }
    
posted @   什么都会有的  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示