⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1.cpp

📁 Knuth的快速模式匹配算法改良
💻 CPP
字号:
//需要用到的库函数
# include <iostream.h>
# include "string.h"
# include <string.h>
# include <stdlib.h>
# include <assert.h>
//STEP 1 : 定义类sting
class string
{
//类string的公有成员
public:
	    //将str和size设为公有,方便以后调用
		char *str;
        int size;
		//用到的成员函数
        int strlen(char *s);
	    string(char *s);
		string substr(int index,int count);
};
//STEP 2 :定义成员函数
//2.1计算字符串s.str的长度
int string::strlen(char *s)
{
    int i=0;
	while(*s!='\0')
	{
		i++;                                          //计数器
		s++;
	}
	return i;                                         //返回字符串长度
}
//2.2转换构造函数:把char *类型转换为string类型
string::string(char *s)
{
	size=strlen(s);                                   //计算字符串的长度
	str=new char[size+1];                             //分配内存
	assert(str!=0);                                   //在分配内存失败时终止
	strcpy(str,s);//把字符串直接拷贝到对象中
}
//2.3从母串s.str提取子串函数,从index开始提取长度为count的子串
string string::substr(int index,int count)
{
	int i;
	int left=size-index;                              //自下标left向右计数到串尾
	string temp="0";
	char *p,*q;
    if(count>left)count=left;                         //若count超过自left以右子串的长度,则把count缩小
	delete [] temp.str;                               //释放原来存储的空间
	temp.str=new char [count+1];
	assert(temp.str!=0);                              //若开辟动态存储空间失败,则退出正常运行
	p=temp.str;                                       //p的内容为指针,指向暂无内容的字符数组首字符处
    q=&str[index];                                    //q的内容为指针,指向标准串str数组下标index处
	for(i=0;i<count;i++) *p++=*q++;                   //将s.str赋值给temp.str
	*p=0;                                             //使temp.str的结尾为'\0'
	temp.size=count;
	return temp;                                      //返回提取出的子串
}
//2.4计算模板串特征向量
int * Next(string p)
{
	int m=p.size;
	int *N=new int[m];                                //开辟动态存储特征向量的空间
	assert(N!=0);                                     //开辟动态空间失败则报错跳出程序
	N[0]=0;                                           //模板串下标j=0的字符特征向量为0
    for (int i=1;i<m;i++)                             //对模板串每一位进行分析
	{
		int k=N[i-1];                                 //根据特称向量的递归定义,假设已知第i-1位特征向量
		while(k>0&&p.str[i]!=p.str[k]&&p.str[i]!='?'&&p.str[i]!='*')
				k=N[k-1];                             //用递归方法计算特征向量
        if (p.str[i]==p.str[k]||p.str[i]=='?'&&p.str[i]!='*')
				N[i]=k+1;
		else N[i]=0;                                  //其他情况,包括第i位为"*"特征值置零
	}
	return N;                                         //返回特征向量数组
}
//2.5模式匹配核心算法,参考书上KMP算法思想并进行了改进
int KMP(string s,string p,int *N,int startindex)
{
                                            
	int lastindex=s.size-p.size;
	if((lastindex-startindex)<0)
	return (-1);                                      //开始匹配位置过大匹配失败
	int i;                                            //指向标准串s的游标
	int j=0;                                          //指向模板串p的游标
    for(i=startindex;i<=s.size;i++)
	{   
		//先讨论只含"?"的情况
		while(p.str[j]!=s.str[i]&&j>0&&p.str[j]!='?'&&p.str[j]!='*')
		{//N循环,不考虑"?"和"*"
           j=N[j-1];//与标准串当前字符匹配的模板串下标
		   i=i-j;
		   //i回溯,根据KMP算法思想在模作最坏的打算,设i的前一位是"?"
		   //由于"?"的通配特性,根据KMP算法思想在模式匹配中"?"的特征值是动态变化的
		   //若用KMP原始算法的N循环来搜索模板串的匹配位置那么一定会出现漏配
		   //根据前面Next函数的定义,不妨使用回溯的方法,让i回到i-j位并让j=0
		   //这时标准串的第i位又重新与模板串的起始位匹配
		   //这样避免讨论"?"的特征值
		   j=0;                                       //使模板串的首位对准标准串回溯的后的第i位
		};
		if(p.str[j]==s.str[i]||p.str[j]=='?'&&p.str[j]!='*')
	    j++;
		if(j==p.size&&p.str[j]!='*')
		{
			return (i-j+1);                           //匹配成功返回标准串匹配模板串的下标位置
            break;
		}
		//再讨论遇到"*"号的情况
		//这样做的原因一方面是此时"*"前的模板串已经与标准串匹配
		//另一方面是为了方便后面可以用递归方法进行模式匹配
		if(p.str[j]=='*')
		{
			string s1="0",p1="0";                     //声明两个string型变量,用于存放"*"后面的模板串与标准串
			int ls=s.strlen(s.str),lp=p.strlen(p.str);//计算"*"后标准串与模板串长度
		    s1=s.substr(i+1,ls-i-1);                  //将"*"后的标准串取出,另存为s1
            p1=p.substr(j+1,lp-j-1);                  //将"*"后的模板串取出,另存为p1
			int *M=Next(p1);                          //计算新模板串p1的特征向量,并将其存到数组M中
			if(KMP(s1,p1,M,0)!=-1&&p.str[0]!='*')return i-j+1;
			//用递归的方法对s1与p1进行模式匹配,即遇见"*"便将原模板串以"*"为界一分为二
			//对"*"后的标准串与模板串进行模式匹配,若最终匹配成功便返回标准串匹配模板串的下标位置
			if(KMP(s1,p1,M,0)!=-1&&p.str[0]=='*')return 0;
			//对于"*"在第一位的情况要特殊考虑,这时如果"*"后的标准串与模板串模式匹配成功则返回0
		}
	}
	return (-1);                                      //整个模式匹配失败
}
//STEP 3 :模式匹配算法主程序 
void main()
{
	char s[100],p[100];                               //声明两个字符型数组,用来存放标准串与模板串
	int k;
	cout<<"*******************模式匹配算法*******************";
	cout<<"\n";
	cout<<"输入标准串 S : ";
	cin>>s;
	cout<<"输入模板串 P : ";
	cin>>p;
    cout<<"设定搜索起始下标 : i = ";
	cin>>k;
    string S=s,P=p;                                   //将输入的char型标准串与模板串转换为自定义的string型
    int *N=Next(P);                                   //调用Next函数
	int K=KMP(S,P,N,k);                               //调用KMP函数
	cout<<"标准串匹配模板串的下标位置为 : i = ";
	cout<<K;
	cout<<"\n";
	if(K!=-1) cout<<"模 式 匹 配 成 功!";
	else cout<<"模 式 匹 配 失 败!"; 
	cout<<"\n";
    
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -