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

📄 matchall.cpp

📁 一个值得学习的模式匹配改进的KMP算法
💻 CPP
字号:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
class NoMem{};
class OutOfBounds{};

class String
{ 
public:
	String(char *s="");
	String(const String& s);
	~String();
	String& operator=(const String& s);
	bool  operator==(const String& s)const;
	int Length()const;
	String operator+(const String& s)const;
	void  operator+=(const String& s);
	int   Find(char c,int start)const;
	String  SubStr(int index,int count)const;
	void  Insert(const String& s,int index);
	void  Delete(int index, int count);
	int ReadString(istream &is=cin,char delimiter='\n');
	void  PrintString( )const;
	int  Match(String& t,int &i);
	void Prefix();
	void ModifiedPrefix();
	//private:
	char *str; 
	int  size;  
	int  *pre; //前缀函数数组
};

String::String(char *s)
{
	int n;
	n=strlen(s)+1;
	//为字符数组分配空间
	str=new char[n];
	//若空间分配失败则抛出异常
	if (str==0)  throw NoMem();
	size=n;
	//将字符串拷贝到本对象字符数组中
	strcpy(str,s);
	//为前缀函数数组分配空间
	pre=new int[size];
	if  (pre==0)   throw  NoMem();
}

String::String(const String& s)
{
	int n;
	n=s.size;
	//为本对象的字符数组分配空间
	str=new char[n];
	if (str==0)  throw NoMem();
	size=n;
	//将对象s的字符数组拷贝到本对象的字符数组中
	strcpy(str,s.str);
	//为前缀函数数组分配空间
	pre=new int[size];
	if  (pre==0)  throw  NoMem();
}


String::~String()
{ 
	//释放本对象字符数组所占用空间 
	delete  []str; 
	delete []pre;
}

String&  String::operator=(const String& s)
{
	//若本对象字符数组空间不等于s的字符数组空间
	if (size!=s.size)
	{
		//删除本对象字符数组空间
		delete []str;
		//为本对象分配一块与s的字符数组同等大小的空间
		str=new char[s.size];
		if (str==0)  throw  NoMem();
		size=s.size;
	}
	//将s的字符数组拷贝到本对象的字符数组中
	strcpy(str,s.str);
	//返回赋值后的本类对象
	return *this;
}

bool String::operator==(const String& s)const
{
	return strcmp(str,s.str)==0;
}

int String::Length( )const
{
	return size-1;
}

String String::operator+(const String& s) const
{
	//创建新串对象temp 
	String  temp;
	//释放temp的空串所占用空间
	delete  []temp.str;
	//为temp的字符数组分配空间,以存放连接后的串
	int  n=size+s.size-1;
	temp.str=new char[n];
	if (temp.str==0)    throw  NoMem( );
	temp.size=n;
	//将本对象存放的串拷贝到temp中
	strcpy(temp.str,str);
	//将s中的串连接至temp的串后
	strcat(temp.str,s.str);
	//返回串对象temp
	return  temp;
}

void String::operator+=(const String& s)
{ char *temp;
//为存放连接后的串的字符数组temp分配空间
temp=new char[size+s.size-1];
if (temp==0)  throw NoMem();
//将本对象存放的串拷贝到temp中
strcpy(temp,str);
//将s中存放的串连接至temp中串的后部
strcat(temp,s.str);
//释放本对象的数组空间,令temp成为其数组空间
delete []str;
str=temp;
size=size+s.size-1;	
}

int  String::Find(char c,int start) const
{ 
	//若start向下越界,则令start=0
	if (start<0)   start=0;
    //若start向上越界,则查找失败,返回-1
	if (start>size-1)  return -1;
    /*使用strchr函数在当前串的位置start起查找字符
    c的首次出现位置,令p指向找到的字符*/
	char *p=strchr(&str[start],c);
	//若查找失败,返回-1
	//	if (p==0)  return -1;
	//若查找成功,返回该字符所在下标
	//	return  p-str;
	int ret;
	if(p!=0)
		ret=int(p-str);
	else ret=-1;
	return ret;
}


String  String::SubStr(int index,int count)const
{ //若下标<0,则令其为0
	if (index<0)  { count+=index;  index=0; }
    //若子串的字符个数count<0,则抛出越界异常
    if (count<0)   throw OutOfBounds(); 
    /*若下标超出或等于串长,或者子串字符个数
    为0,   则返回空串对象*/
    String s;
    if (index>=size-1 || count==0)  return  s;
	/* 若子串字符个数多于串中从index开始至串尾的   字符个数,令count为串中从index开始的字符个数*/
    if (count>size-index-1)   count=size-index-1;
	//释放串对象s的字符数组空间
    delete []s.str;
	//为串对象s的字符数组分配空间
	s.str=new char[count+1];
	
	if (s.str==0)  throw NoMem();
	s.size=count+1;
	//将子串拷贝到s中并设置串结束标记’\0’
	
	char  *p,*q;  int  i;
	for ( i=0,p=s.str,q=&str[index]; i<count; i++)
		*p++=*q++;
	*p=0;
	//返回存放子串的串对象s
	return s;
}


void  String::Insert(const String &s,int index)
{
	//若插入位置向下越界,则令其为0
	if (index<0)  index=0;
	//若插入位置向上越界,则令其为串尾位置
	if (index>size-1)  index=size-1;
	//为字符数组temp分配空间,以存放插入后的串
	char *temp;
	temp=new char[size+s.size-1];   
	if (temp==0)  throw NoMem();
	//将当前串的前index个字符拷贝到temp中
	char *p,*q;  int i;
	for (i=0,p=temp,q=str; i<index; i++)
		*p++=*q++;
	//将s中存放的串放至temp中
	strcpy(p,s.str);
	p+=s.size-1;
	/*若当前串除前index个字符外还有字符,将
	剩余字符放至temp中*/
	strcpy(p,&str[index]);
	
	delete []str;
	str=temp;
	size=size+s.size-1;
}

void  String::Delete(int index,int count)
{ //若被删字符数count<0,则抛出异常
    if (count<0)  throw OutOfBounds();
    /*若被删位置向上越界或被删字符数为0,则 
	不做任何删除操作*/
    if (index>=size-1 || count==0)  return;
	/*若被删位置向下越界,则令被删字符数减少
	并令被删位置为0*/
    if (index<0)  { count+=index; index=0; }
	/*若被删字符数count多于串中从位置index开始的所有字符,则令count为串中从index开始的字符数目*/
    if (count>size-index-1)  count=size-index-1;
	//为字符数组分配空间以存放删除后的串
	char *temp;
    temp=new char[size-count];
    if (temp==0)  throw NoMem();	
	
	/*将当前串的前index个字符拷贝到temp中
	并设置串结束符*/
	strncpy(temp,str,index);
	temp[index]='\0';
	/*若当前串从位置index起删除count个字符
	后还有剩余字符,则将其拷贝到temp中*/
	if (index<size-count-1)    
		strcat(temp,&str[index+count]);
	/*释放当前串对象的字符数组所占用空间,并令temp成为其数组空间*/
	delete []str;
	str=temp;
	size=size-count;
}

int String::ReadString(istream & istr,char delimiter)
{
	char temp[256];
	//从输入流中接收一系列字符至temp,以delimiter为终止符
	if (istr.getline(temp,256,delimiter))
	{ //释放本对象的字符数组空间
		delete []str;
		int n=strlen(temp)+1;
		//为本对象申请新的字符数组空间存放输入的字符
		str=new char[n];
		if (str==0)  throw NoMem();
		size=n;
		//将temp中字符串拷贝到当前串中
		strcpy(str,temp);
		//返回接收到的字符数
		return size-1;
	}
	//若字符接收失败,则返回-1	
	else return -1;  
} 



void String::PrintString()const
{cout<<str<<endl;}

void String::Prefix()
{
	int m=Length();
	delete[]pre;
	pre=new int[m+1];
	if (pre==0)throw NoMem();
	pre[0]=0;
	int k=0;
	for (int i=1;i< m;i++)
	{
		while((*(str+i-1)!=*(str+k))&&(k>0))
			k=pre[k];
		if (*(str+i-1)=*(str+k))
			pre[i]=++k;
		else pre[i]=0;
	}
	
}

void String::ModifiedPrefix()
{
	int *f;
	int m=Length();
	f=new int[m+1];
	Prefix();
	for (int i=1;i<=m;i++)
		f[i]=pre[i];
	for(i=1;i<m;i++)
	{
		int k=f[i];
		if((k==0) ||(*(str+i)!=*(str+k)))
			pre[i]=k;
		else pre[i]=pre[k];
	}
	delete []f;
}
int String::Match(String&t,int &i)
{   
	int j=0;
    int n=Length(),m=t.Length();     
	t.ModifiedPrefix();
	while( (i<=n)&& (j<m) )
	{
		if (str[i-1]==t.str[j])
		{
			i++;
			j++;
		}
		else 
			if(j==0)i++;
			else j=t.pre[j-1];
	}
	if(j<m)
		return 0;
	else
		return i-m;
}

void Mov(int Temp,int n,int flag[])
{
	for(int i= 1;i<= n;i++)
		if(flag[i]== 0)
		{
			flag[i]= Temp;
			return;
		}
}

int main()
{
	int n,m,i;
	string str1,str2;
	ifstream in("input.txt");
	getline(in,str1);
	getline(in,str2);
	
	n=str1.length()+1;
	m=str2.length()+1;
	int *flag= new int[n];
	for(i= 1;i<= n-1;i++) flag[i]=0;
	String Str1,Str2;
	
	Str1.str=new char[n];
	Str1.size=n;
	for(i= 0;i<n-1;i++) Str1.str[i]=str1.at(i);
	Str2.str=new char[m];
	Str2.size=m;
	for(i= 0;i<m-1;i++) Str2.str[i]=str2.at(i);
	
	i= 1;
	while(i<= n-1)
	{
		int Temp= Str1.Match(Str2,i);
		if(Temp!= 0)
		{
			Mov(Temp,n-1,flag);
			i= Temp+1;
		}
	}
	ofstream out("output.txt");
	if (flag[1]==0)
		out<<"0";
    else
		for(i= 1;i<= n-1;i++)
			if(flag[i]!= 0)
				out<<flag[i]<<" ";
			return 0;
}

⌨️ 快捷键说明

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