KMP字符串模式匹配源代码(C++),数据结构学习

主函数代码

#include <iostream>				// 编译预处理命令
#include <cstring>				// 包含C函数strlen()、strcpy()、strncpy()、strcat()和strcmp()的声明(string.h与cstring是C的头文件)
#include <cstdio>			    // 包含EOF的声明(stdio.h与cstdio是C的头文件)
using namespace std;			// 使用命名空间std 
#include "kmp_match.h"			// KMP算法

int main()
{	// 测式KMP字符串模式匹配算法
	CharString targetStr("this is a string");
	CharString patternStr("is");

	cout << KMPIndex(targetStr, patternStr) << endl;
	cout << KMPIndex(targetStr, patternStr, 3) << endl;
	cout << KMPIndex(targetStr, patternStr, 6) << endl;
	targetStr=patternStr;
	cout << KMPIndex(targetStr, patternStr) << endl;

	return 0;						// 返回值0, 返回操作系统
}

头文件“kmp_match.h”

#ifndef __KMP_MATCH_H__
#define __KMP_MATCH_H__

#include "char_string.h"			// 串类

// KMP匹配算法
void GetNext(const CharString &patternStr, int next[])
// 操作结果: 求模式串patternStr的next数组的元素值
{
	next[0] = -1;					// 由next[0] = -1开始进行递推
	int curPos = 0, nextPos = -1;	// curPos为数组当前元素的下标(相当于教材分析中的j),nextPos为next[curPos](相当于教材
									// 分析中的k),next[curPos] = nextPos(相当于教材分析中的next[j] = k)成立的初始情况
	while (curPos < patternStr.Length() - 1)		
	{	// 数组next的下标范围为0 ~ patternStr.Length() - 1,通过递推方式求得next[curPos+1]的值
		if (nextPos == -1)
		{	// 不存在nextPos满足patternStr[nextPos]==patternStr[curPos]或curPos==0
			next[curPos + 1] = 0;	// next[curPos+1]=0
			curPos++; nextPos = 0;	// 由于已求得next[curPos+1] = 0,所以curPos更新为curPos+1,nextPos更新为0
		}
		else if (patternStr[nextPos] == patternStr[curPos])
		{	// 此时相当于教材分析中的next[j+1] = next[j]+1
			next[curPos + 1] = nextPos + 1;	// 由于patternStr[nextPos]=patternStr[curPos],所以next[curPos+1]=next[curPos]+1=nextPos + 1
			curPos++; nextPos++;	// 由于已求得next[curPos+1]=nextPos+1,所以curPos更新为curPos+1,nextPos更新为nextPos+1
		}
		else
		{	// patternStr[nextPos]与patternStr[curPos]不匹配
			nextPos = next[nextPos];// 寻求新的匹配字符
		}
	}
}


int KMPIndexHelp(const CharString &targetStr, const CharString &patternStr, int pos, int next[])
// 操作结果: 通过next数组查找模式串patternStr第一次在目标串targetStr中从第pos个字符开始出现的位置
{
	int curTargetStrPos = pos, curPatternStrPos = 0;		// curTargetStrPos相当于教材分析中的i,curPatternStrPos相当于教材分析中的j
	while (curTargetStrPos < targetStr.Length() && curPatternStrPos < patternStr.Length())
	{	
		if (curPatternStrPos == -1)
		{	// 此时表明patternStr中任何字符都不再与targetStr[curTargetStrPos]进行比较,下次patternStr[0]与targetStr[curTargetStrPos+1]开始进行比较
			curTargetStrPos++; curPatternStrPos = 0;
		}
		else if (patternStr[curPatternStrPos] == targetStr[curTargetStrPos])
		{	// patternStr[curTargetStrPos]与targetStr[curPatternStrPos]匹配
			curTargetStrPos++; curPatternStrPos++;			// 模式串patternStr与目标串targetStr的当前位置向后移
		}
		else
		{	// patternStr[curPatternStrPos]与targetStr[curTargetStrPos]不匹配
			curPatternStrPos = next[curPatternStrPos];		// 寻找新的模式串patternStr的匹配字符位置
		}
	}

	if (curPatternStrPos < patternStr.Length()) return -1;	// 匹配失败
	else return curTargetStrPos - curPatternStrPos;			// 匹配成功
}

int KMPIndex(const CharString &targetStr, const CharString &patternStr, int pos = 0)
// 操作结果: 查找模式串patternStr第一次在目标串targetStr中从第pos个字符开始出现的位置
{
	int *next = new int[patternStr.Length()];				// 为数组next分配空间
	GetNext(patternStr, next);								// 求模式串patternStr的next数组的元素值
	int result = KMPIndexHelp(targetStr, patternStr, pos, next);	
		// 返回模式串patternStr第一次在目标串targetStr中从第pos个字符开始出现的位置
	delete []next;											// 释放next所占用的存储空间
	return result;											// 返回匹配结果
}

#endif

头文件“char_string.h”

#ifndef __CharString_H__
#define __CharString_H__

#include "lk_list.h"													// 线性链表

// 串类
class CharString 
{
protected:
// 数据成员:
	mutable char *strVal;												// 串值
	int length;															// 串长	

public:                           
// 抽象数据类型方法和相关方法声明及重载编译系统默认方法声明:
	CharString();														// 构造函数 
	virtual ~CharString();												// 析构函数
	CharString(const CharString &source);								// 复制构造函数
	CharString(const char *source);										// 从C风格串转换的构造函数
	CharString(LinkList<char> &source);									// 从线性表转换的构造函数
	int Length() const;													// 求串长度			 
	bool Empty() const;													// 判断串是否为空
	CharString &operator =(const CharString &source);					// 重载赋值运算符
	const char *ToCStr() const { return (const char *)strVal; }			// 将串转换成C风格串
	char &operator [](int pos) const;									// 重载下标运算符
};

// 串相关操作
CharString Read(istream &input);										// 从输入流读入串
CharString Read(istream &input, char &terminalChar);					// 从输入流读入串,并用terminalChar返回串结束字符
void Write(const CharString &s);										// 输出串
void Concat(CharString &target, const CharString &source);				// 将串source连接到串target的后面
void Copy(CharString &target, const CharString &source);				// 将串source复制到串target
void Copy(CharString &target, const CharString &source, int n);			// 将串source复制n个字符到串target 
int Index(const CharString &target, const CharString &pattern, int pos = 0);// 查找模式串pattern第一次在目标串target中从第pos个字符开始出现的位置
CharString SubString(const CharString &s, int pos, int len);		// 求串s的第pos个字符开始的长度为len的子串
bool operator ==(const CharString &first, const CharString &second);	// 重载关系运算符==
bool operator <(const CharString &first, const CharString &second);		// 重载关系运算符<
bool operator >(const CharString &first, const CharString &second);		// 重载关系运算符>
bool operator <=(const CharString &first, const CharString &second);	// 重载关系运算符<=
bool operator >=(const CharString &first, const CharString &second);	// 重载关系运算符>=
bool operator !=(const CharString &first, const CharString &second);	// 重载关系运算符!=

// 串类及相关操作的实现部分
CharString::CharString()
//  操作结果:初始化串 
{
	length = 0;															// 串长度为0
	strVal = NULL;														// 空串
}

CharString::~CharString()
// 操作结果:销毁串,释放串所占用空间
{
	delete []strVal;													// 释放串strVal
}

CharString::CharString(const CharString &source)
// 操作结果:由串source构造新串——复制构造函数
{
	length = strlen(source.ToCStr());									// 串长
	strVal = new char[length + 1];										// 分配存储空间
	strcpy(strVal, source.ToCStr());									// 复制串值
}

CharString::CharString(const char *source)
// 操作结果:从C风格串转换构造新串——转换构造函数
{
	length = strlen(source);											// 串长
	strVal = new char[length + 1];										// 分配存储空间 
	strcpy(strVal, source);												// 复制串值
}

CharString::CharString(LinkList<char> &source)
// 操作结果:从线性表转换构造新串——转换构造函数
{
	length = source.Length();											// 串长
	strVal = new char[length + 1];										// 分配存储空间 
	for (int pos = 0; pos < length; pos++) 
	{	// 复制串值
		source.GetElem(pos + 1, strVal[pos]);
	}
	strVal[length] = '\0';												// 串值以'\0'结束	
}

int CharString::Length() const
// 操作结果:返回串长度			 
{
	return length;
}

bool CharString::Empty() const
// 操作结果:如果串为空,返回true,否则返回false
{
	return length == 0;
}

CharString &CharString::operator =(const CharString &source)
// 操作结果:重载赋值运算符
{
	if (&source != this)
	{
		delete []strVal;												// 释放原串存储空间
		length = strlen(source.ToCStr());								// 串长
		strVal = new char[length + 1];									// 分配存储空间 
		strcpy(strVal, source.ToCStr());								// 复制串值
	}
	return *this;
}

char &CharString::operator [](int pos) const
// 操作结果:重载下标运算符
{
	return strVal[pos];
}

CharString Read(istream &input)
// 操作结果:从输入流读入串
{
	LinkList<char> temList;												// 临时线性表
	char ch;															// 临时字符
	while ((ch = input.peek()) != EOF &&								// peek()从输入流中取一个字符,输入流指针不变
		(ch = input.get()) != '\n')										// get()从输入流中取一个字符,输入流指针指向下一字符
	{	// 将输入的字符追加线性表中
		temList.Insert(temList.Length() + 1, ch);
	}
	return temList;														// 返回由temList生成的串
}

CharString Read(istream &input,char &terminalChar)
// 操作结果:从输入流读入串,并用terminalChar返回串结束字符
{
	LinkList<char> temList;												// 临时线性表
	char ch;															// 临时字符
	while ((ch = input.peek()) != EOF &&								// peek()从输入流中取一个字符,输入流指针不变
		(ch = input.get()) != '\n')										// get()从输入流中取一个字符,输入流指针指向下一字符
	{	// 将输入的字符追加线性表中
		temList.Insert(temList.Length() + 1, ch);
	}
	terminalChar = ch;													// 用terminalChar返回串结束字符
	return temList;														// 返回由temList生成的串
}

void Write(const CharString &s)
// 操作结果:输出串
{
	cout << s.ToCStr() << endl;											// 输出串值
}

void Concat(CharString &target, const CharString &source)
// 操作结果:将串source连接到串target的后面
{
	const char *cFirst = target.ToCStr();								// 指向第一个串
	const char *cSecond = source.ToCStr();								// 指向第二个串
	char *cTarget = new char[strlen(cFirst) + strlen(cSecond) + 1];		// 分配存储空间
	strcpy(cTarget, cFirst);											// 复制第一个串
	strcat(cTarget, cSecond);											// 连接第二个串
	target = cTarget;													// 串赋值
	delete []cTarget;													// 释放cTarget
}

void Copy(CharString &target, const CharString &source)
// 操作结果:将串source复制到串target
{
	const char *cSource = source.ToCStr();								// 初始串
	char *cTarget = new char[strlen(cSource) + 1];						// 分配存储空间
	strcpy(cTarget, cSource);											// 复制串
	target = cTarget;													// 串赋值
	delete []cTarget;													// 释放串cTarget
}

void Copy(CharString &target, const CharString &source, int n)
// 操作结果:将串source复制n个字符到串target 
{
	const char *cSource = source.ToCStr();								// 初始串
	int len = (int)strlen(cSource) < n ? (int)strlen(cSource) : n;		//目标串长
	char *cTarget = new char[len + 1];									// 分配存储空间
	strncpy(cTarget, cSource, n);										// 复制串
	cTarget[len] = '\0';												// 串值以'\0'结束
	target = cTarget;													// 串赋值
	delete []cTarget;													// 释放串cTarget
}

int Index(const CharString &target, const CharString &pattern, int pos)
// 操作结果:如果匹配成功,返回模式串pattern第一次在目标串target中从第pos
//	个字符开始出现的位置, 否则返回-1
{
	const char *cTarget = target.ToCStr();								// 目标串
	const char *cPattern = pattern.ToCStr();							// 模式串
	const char *ptr=strstr(cTarget + pos, cPattern);					// 模式匹配
	if (ptr == NULL)
	{	// 匹配失败	
		return -1; 
	}
	else
	{	// 匹配成功	
		return ptr - cTarget;
	}
}

CharString SubString(const CharString &s, int pos, int len)
// 初始条件:串s存在,0 <= pos < s.Length()且0 <= len <= s.Length() - pos
// 操作结果:返回串s的第pos个字符开始的长度为len的子串
{
	if (0 <= pos && pos < s.Length() && 0 <= len)
	{	// 返回串s的第pos个字符开始的长度为len的子串
		len = (len < s.Length() - pos) ? len : (s.Length() - pos);		// 子串长
		char *sub = new char[len + 1];									// 分配存储空间
		const char *str = s.ToCStr();									  // 生成C风格串
		strncpy(sub, str + pos, len);									// 复制串
		sub[len] = '\0';												// 串值以'\0'结束
		return sub;														// 返回子串sub
	}
	else
	{	// 返回空串
		return "";														// 返回空串
	}
}

bool operator ==(const CharString &first, const CharString &second)
// 操作结果:重载关系运算符==
{
	return strcmp(first.ToCStr(), second.ToCStr()) == 0;
}

bool operator <(const CharString &first, const CharString &second)
// 操作结果:重载关系运算符<
{
	return strcmp(first.ToCStr(), second.ToCStr()) < 0;
}

bool operator >(const CharString &first, const CharString &second)
// 操作结果:重载关系运算符>
{
	return strcmp(first.ToCStr(), second.ToCStr()) > 0;
}

bool operator <=(const CharString &first, const CharString &second)
// 操作结果:重载关系运算符<=
{
	return strcmp(first.ToCStr(), second.ToCStr()) <= 0;
}

bool operator >=(const CharString &first, const CharString &second)
// 操作结果:重载关系运算符>=
{
	return strcmp(first.ToCStr(), second.ToCStr()) >= 0;
}

bool operator !=(const CharString &first, const CharString &second)
// 操作结果:重载关系运算符!=
{
	return strcmp(first.ToCStr(), second.ToCStr()) != 0;
}


#endif

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值