基于改进KMP算法的字符文件子串查找

实验内容及要求:

从键盘输入字符文件名以及子串,用改进KMP算法在字符文件中实现子串查找。要求程序输出子串的改进nextval数组元素值以及子串在文件中成功匹配的次数(查找失败输出成功匹配次数为0)。

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<fstream>
#define MAX_SIZE 30
using namespace std;
void read(char* filename, char* s)              //读取数据,filename代入不同的文件名,s为主串
{
	char c;
	int i = 0;
	ifstream infile(filename);
	if (!infile)                           //打开文件失败输出提示信息
	{
		cout << "file open error!" << endl;
		exit(0);
	}
	while (1)                              //读入字符,保存在主串中
	{
		infile >> c;
		if (infile.eof())
			break;
		s[i] = c;
		i++;
	}
	s[i] = '\0';
	cout << "主串为: ";                    //输出主串
	for (i = 0; i < strlen(s); i++)
		cout << s[i];
	cout << endl;
	infile.close();
}
void get_next(char* t, int next[])             //求next数组,t为子串
{
	int j=0, i= next[0]=-1;
	while (j < strlen(t) )           
	{
		if (i == -1 || t[j ] == t[i])
			next[++j] = ++i;
		else
			i = next[i];
	}
}
void get_nextval(char* t, int nextval[], int next[])    //求nextval数组,t为子串
{
	int j, k;
	nextval[0] = k = -1;
	j = 1;
	while (t[j])
	{
		if (k == -1 || t[j - 1] == t[k])
			if (t[++k] == t[j])
				nextval[j++] = nextval[k];
			else
				nextval[j++] = k;
		else
			k = nextval[k];
	}
	nextval[strlen(t)] = next[strlen(t)];   //nextval[m]即为next[m]的值
}
int KMP(char* s, char* t, int nextval[], int& num)    /*KMP算法:子串的模式匹配,s为主
															串,t为子串,num记录匹配的次数*/
{
	int k = 1;
	int i, j, flag = 1, location;           /*flag为标量,第一次匹配时flag为1,否则flag为
											0,location记录第一次匹配的位置下标*/
	i = j = 0;
	while (s[i] && (j == -1 || t[j]))
	{
		if (j == -1 || s[i] == t[j])
		{
			i++;
			j++;
		}
		else
			j = nextval[j];
		if (!t[j])
		{
			
			if (flag == 1)                  //第一次匹配,location记录匹配的位置下标
			{
				location = i - j;
				flag = 0;
			}
			cout << endl<<"第" << k++ << "次匹配的位置为: " << i-j << endl;
			
			j = nextval[strlen(t)];         //匹配成功后,j就从nextval[m]开始继续查找
			num++;                          //num记录匹配的次数
		}
	}
	if (flag == 1)                               //flag恒为1表示没有一次成功的匹配
	{
		location = -1;                      //location为-1表示匹配失败
		cout <<endl<< "匹配失败!"<<endl;
	}
	cout << endl;
	return location;                            //返回第一次匹配的位置下标
}

int main()
{
	//  location记录第一次匹配的位置,num记录匹配的次数
	int nextval[MAX_SIZE], next[MAX_SIZE], i, location, num = 0;  
	char t[MAX_SIZE], s[MAX_SIZE], filename[MAX_SIZE];        //t为子串,s为主串,filename为文件的名称
	cout << "请输入文件的名称: ";
	cin >> filename;
	read(filename, s);                      //从文件中读取主串
	cout << "请输入子串: ";
	cin >> t;                               //输入子串
	while (strlen(t) > strlen(s))           //输入错误,重新输入
	{
		cout << "输入错误(子串长度大于主串长度),请重新输入: ";
		cin >> t;
	}
	get_next(t, next);
	cout << "next数组为:    "<<endl;
	for (i = 0; i < strlen(t) ; i++)     //next数组多一个元素,用来记录子串回溯的位置
		cout << '\t' << next[i];
	get_nextval(t, nextval, next);
	cout << endl << "nextval数组为: " << endl;;
	for (i = 0; i < strlen(t) ; i++)     //nextval[m]即为next[m]的值,记录子串回溯的位置
		cout << '\t' << nextval[i] ;
	location = KMP(s, t,nextval, num);
	cout <<"子串在文件中成功匹配的次数为: "<< num << endl;
	return 0;
}

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值